I have an function in postgresql. I don't know whether I made it a bit complicated. I have a select query and I need to append some more expressions into that. I am passing those expressions as input parameters.
CREATE OR REPLACE FUNCTION get_alldocuments(currUser text,
queryExp text,
query0 text,
query1 text)
RETURNS TABLE(fileleafref text,contenttypename text,fsobjtype text,id integer,conttypeid integer,contenttypeid integer,docicon text,encodedabsurl text,refId integer,filesizedisplay integer,created date,
createdby text,version text) AS $$
BEGIN
RETURN QUERY EXECUTE 'select distinct c.fileleafref, ct.contenttypename,c.fsobjtype,c.id,c.conttypeid,d.contenttypeid,c.docicon,c.encodedabsurl,d.ref_id as RefId,c.filesizedisplay,d.created,
d.createdby,c.version from public.documents d inner join public.documentcontent c on d.id=c.documentid inner join conttype ct on ct.id = c.conttypeid
where '
|| quote_literal(queryExp)
|| ' versionflag=true and c.permissiontype ="1" or (c.permissiontype="3" and c.createdby =currUser) order by d.created desc limit 300)
union
(select distinct c.fileleafref, ct.contenttypename,c.fsobjtype,c.id,c.conttypeid,d.contenttypeid,c.docicon,c.encodedabsurl,d.ref_id as RefId,c.filesizedisplay,d.created,
d.createdby,c.version from public.documents d inner join public.documentcontent c on d.id=c.documentid inner join conttype ct on ct.id = c.conttypeid '
|| quote_ident(query0) ||
' where' || quote_ident(queryExp) || 'versionflag=true '|| quote_ident(query1) ||
' order by d.created desc limit 300)';
END
$$ LANGUAGE plpgsql;
in the function I am trying to append different expressions at different places of my select query.
The input variables are
currUser - user1
queryExp - metadata #> ''{"Year":"2011"}'' and metadata #> ''{"Country":"US"}'' and
query0 - ,jsonb_array_elements(c.securitygppermission) as e(users) ,jsonb_array_elements_text(c.userspermission) as p(perm)
query1 - and (c.permissiontype='2' and e.users ->>'Deny'='false' and e.users ->>'Allow'='true' and e.users ->>'GroupName'='Manager' and p.perm ='user1')
The complete select query sample is
select * from get_alldocuments('user1','metadata #> ''{"Year":"2011"}'' and metadata #> ''{"Country":"US"}'' and ',',jsonb_array_elements(c.securitygppermission) as e(users) ,jsonb_array_elements_text(c.userspermission) as p(perm)','and (c.permissiontype="2" and e.users ->>"Deny"="false" and e.users ->>"Allow"="true" and e.users ->>"GroupName"="Manager" and p.perm ="user1")')
While executing the function its showing an error like
ERROR: syntax error at or near "versionflag"
LINE 3: ...11"}'' and metadata #> ''{"Country":"US"}'' and ' versionfla...
^
QUERY: select distinct c.fileleafref, ct.contenttypename,c.fsobjtype,c.id,c.conttypeid,d.contenttypeid,c.docicon,c.encodedabsurl,d.ref_id as RefId,c.filesizedisplay,d.created,
d.createdby,c.version from public.documents d inner join public.documentcontent c on d.id=c.documentid inner join conttype ct on ct.id = c.conttypeid
where 'metadata #> ''{"Year":"2011"}'' and metadata #> ''{"Country":"US"}'' and ' versionflag=true and c.permissiontype ="1" or (c.permissiontype="3" and c.createdby =currUser) order by d.created desc limit 300)
union
(select distinct c.fileleafref, ct.contenttypename,c.fsobjtype,c.id,c.conttypeid,d.contenttypeid,c.docicon,c.encodedabsurl,d.ref_id as RefId,c.filesizedisplay,d.created,
d.createdby,c.version from public.documents d inner join public.documentcontent c on d.id=c.documentid inner join conttype ct on ct.id = c.conttypeid ",jsonb_array_elements(c.securitygppermission) as e(users) ,jsonb_array_elements_text(c.userspermission) as p(perm)" where"metadata #> '{""Year"":""2011""}' and metadata #> '{""Country"":""US""}' and "versionflag=true "and (c.permissiontype=2 and e.users ->>""Deny""=""false"" and e.users ->>""Allow""=""true"" and e.users ->>""GroupName""=""Manager"" and p.perm =""user1"")" order by d.created desc limit 300)
CONTEXT: PL/pgSQL function get_alldocuments(text,text,text,text) line 4 at RETURN QUERY
********** Error **********
What is the issue? Am I concatenated in the correct way?
If I parse your query correctly then this parts looks wrong:
where 'metadata #> ''{"Year":"2011"}'' and metadata #> ''{"Country":"US"}'' and ' versionflag=true
Between the where and versionflag=true you have a string literal (single quoted string). So to postgresql it basically looks like you wrote where 'string' versionflag=true which doesn't make any sense. Looks like a comparison and a logical operator are missing.
I resolve the issue. 'quote_indent' created the issue. The final function is
CREATE OR REPLACE FUNCTION public.get_alldocuments(
curruser text,
queryexp text,
query0 text,
query1 text)
RETURNS TABLE(fileleafref character varying, contenttypename character varying, fsobjtype character varying, id integer, conttypeid integer, contenttypeid character varying, docicon character varying, encodedabsurl character varying, refid character varying, filesizedisplay integer, created date, createdby character varying, version character varying)
LANGUAGE 'plpgsql'
COST 100
VOLATILE
ROWS 1000
AS $BODY$
BEGIN
RETURN QUERY EXECUTE '(select distinct c.fileleafref, ct.contenttypename,c.fsobjtype,c.id,c.conttypeid,cast(d.contenttypeid as varchar) as contenttypeid,c.docicon,c.encodedabsurl,d.ref_id as RefId,c.filesizedisplay,cast(d.created as date) created,
d.createdby,c.version from public.documents d inner join public.documentcontent c on d.id=c.documentid inner join conttype ct on ct.id = c.conttypeid
where '
|| queryExp
|| ' versionflag=true and c.permissiontype=''1'' or (c.permissiontype=''3'' and c.createdby =''|| curruser ||'') order by created desc limit 300)
union
(select distinct c.fileleafref, ct.contenttypename,c.fsobjtype,c.id,c.conttypeid,cast(d.contenttypeid as varchar) as contenttypeid,c.docicon,c.encodedabsurl,d.ref_id as RefId,c.filesizedisplay,cast(d.created as date) created,
d.createdby,c.version from public.documents d inner join public.documentcontent c on d.id=c.documentid inner join conttype ct on ct.id = c.conttypeid '
|| query0 ||
' where ' || queryExp || ' versionflag=true ' || query1 ||
'order by created desc limit 300);';
END
$BODY$;
Related
In PgSQL I make huge select, and then I want count it's size and apply some extra filters.
execute it twice sound dumm,
so I wrapped it in function
and then "cache" it and return union of filtered table and extra row at the end where in "id" column store size
with q as (select * from myFunc())
select * from q
where q.distance < 400
union all
select count(*) as id, null,null,null
from q
but it also doesn't look like proper solution...
and so the question: is in pg something like "generator function" or any other stuff that can properly solve this ?
postgreSQL 13
myFunc aka "selectItemsByRootTag"
CREATE OR REPLACE FUNCTION selectItemsByRootTag(
in tag_name VARCHAR(50)
)
RETURNS table(
id BIGINT,
name VARCHAR(50),
description TEXT,
/*info JSON,*/
distance INTEGER
)
AS $$
BEGIN
RETURN QUERY(
WITH RECURSIVE prod AS (
SELECT
tags.name, tags.id, tags.parent_tags
FROM
tags
WHERE tags.name = (tags_name)
UNION
SELECT c.name, c.id , c.parent_tags
FROM
tags as c
INNER JOIN prod as p
ON c.parent_tags = p.id
)
SELECT
points.id,
points.name,
points.description,
/*points.info,*/
points.distance
from points
left join tags on points.tag_id = tags.id
where tags.name in (select prod.name from prod)
);
END;
$$ LANGUAGE plpgsql;
as a result i want see maybe set of 2 table or generator function that yield some intermediate result not shure how exacltly it should look
demo
CREATE OR REPLACE FUNCTION pg_temp.selectitemsbyroottag(tag_name text, _distance numeric)
RETURNS TABLE(id bigint, name text, description text, distance numeric, count bigint)
LANGUAGE plpgsql
AS $function$
DECLARE _sql text;
BEGIN
_sql := $p1$WITH RECURSIVE prod AS (
SELECT
tags.name, tags.id, tags.parent_tags
FROM
tags
WHERE tags.name ilike '%$p1$ || tag_name || $p2$%'
UNION
SELECT c.name, c.id , c.parent_tags
FROM
tags as c
INNER JOIN prod as p
ON c.parent_tags = p.id
)
SELECT
points.id,
points.name,
points.description,
points.distance,
count(*) over ()
from points
left join tags on points.tag_id = tags.id
where tags.name in (select prod.name from prod)
and points.distance > $p2$ || _distance
;
raise notice '_sql: %', _sql;
return query execute _sql;
END;
$function$
You can call it throug following way
select * from pg_temp.selectItemsByRootTag('test',20);
select * from pg_temp.selectItemsByRootTag('test_8',20) with ORDINALITY;
The 1 way to call the function, will have a row of total count total number of rows. Second way call have number of rows plus a serial incremental number.
I also make where q.distance < 400 into function input argument.
selectItemsByRootTag('test',20); means that q.distance > 20 and tags.name ilike '%test%'.
I have a working recursive function down below that returns the hierarchy of a .Net Element, in this example 'ImageBrush'
WITH RECURSIVE r AS (
SELECT id, name, dependent_id, 1 AS level
FROM dotNetHierarchy
WHERE name = 'ImageBrush'
UNION ALL
SELECT g.id, lpad(' ', r.level) || g.name, g.dependent_id, r.level + 1
FROM dotNetHierarchy g JOIN r ON g.id = r.dependent_id
)
SELECT name FROM r;
Now I want to use it inside a function, where the input is a text like 'ImageBrush' which gets inserted in the WHERE statement of the recursive query.
The table dotNetHierarchy has 3 columns: id, name, dependent_id
The following didnĀ“t work with PgAdmin just querying forever without an error:
CREATE OR REPLACE FUNCTION get_hierarchy(inp text) RETURNS
TABLE (id int, name text, id int, lev int) AS
$BODY$
DECLARE
BEGIN
WITH RECURSIVE r AS (
SELECT id, name, dependent_id, 1 AS level
FROM dotNetHierarchy
WHERE name = inp
UNION ALL
SELECT g.id, lpad(' ', r.level) || g.name, g.dependent_id, r.level + 1
FROM dotNetHierarchy g JOIN r ON g.id = r.dependent_id
)
SELECT name FROM r;
return;
END
$BODY$
LANGUAGE plpgsql;
I tried searching google for using recursive querys in functions, but the few results proved not to be working.
I would appreciate any help, thanks in advance.
Your function doesn't return anything. You would at least need a return query, but it's more efficient to use a language sql function to encapsulate a query:
CREATE OR REPLACE FUNCTION get_hierarchy(inp text)
RETURNS TABLE (id int, name text, id int, lev int) AS
$BODY$
WITH RECURSIVE r AS (
SELECT id, name, dependent_id, 1 AS level
FROM dotNetHierarchy
WHERE name = inp
UNION ALL
SELECT g.id, lpad(' ', r.level) || g.name, g.dependent_id, r.level + 1
FROM dotNetHierarchy g JOIN r ON g.id = r.dependent_id
)
SELECT name
FROM r;
$BODY$
LANGUAGE sql;
I write function in PostgreSQL. I am trying to fetch data from db by passing parameters in function .But i am getting error" ERROR: structure of query does not match function result type".
Here i created a function in which i am using union to get unique values.In first select stat. i amsetting value for account total that is used in below code.
Function:
CREATE OR REPLACE FUNCTION GetDeptListForViewModifyJointUsePercentages ( p_nInstID numeric,p_nDeptID numeric)
RETURNS Table(
res_ndept_id numeric,
res_salaryPercent character varying,
res_nclient_cpc_mapping_id numeric,
res_CPCCODE character varying,
res_sdept_name character varying,
res_sclient_dept_id character varying,
res_sAlternateJointUsePercentage character varying
)
AS $$
declare v_AccountTotal numeric(18,2);
BEGIN
RETURN QUERY
select SUM(CAST (coalesce(eam.npayroll_amt, null) AS numeric(18,2))) as AccountTotal
FROM Account acct
INNER JOIN employeeaccountmapping eam
ON eam.nacct_id = acct.naccount_id
AND acct.ninst_id =p_nInstID
where acct.ndept_id =p_nDeptID ;
SELECT *
FROM
(select dep.ndept_id ,( CASE
WHEN v_AccountTotal =0 THEN 0
ELSE Round(SUM(CAST(coalesce(eam.npayroll_amt, null) AS numeric(18,2)) * cac.npercentage_assigned/100) / v_AccountTotal *100,null)
END
) as salaryPercent
,cac.nclient_cpc_mapping_id,client.sclient_cpc AS CPCCODE,
dep.sdept_name,dep.sclient_dept_id,'NO' ASsAlternateJointUsePercentage
FROM account
INNER JOIN employeeaccountmapping eam
ON eam.nacct_id = account .naccount_id AND account .ninst_id=p_nInstID
INNER JOIN accountcpcmapping acm
ON acm.naccount_cpc_mapping_id = account.naccount_cpc_mapping_id
INNER JOIN cpcaccountcpcmapping as cac
ON cac.naccount_cpc_mapping_id=acm.naccount_cpc_mapping_id
INNER JOIN clientcostpoolcodes as client
ON client.nclient_cpc_mapping_id=cac.nclient_cpc_mapping_id
INNER JOIN mastercostpoolcodes
ON mastercostpoolcodes .nmaster_cpc_id= client.nmaster_cpc_id
INNER JOIN department as dep
ON account.ndept_id=dep.ndept_id and dep.balternate_jointuse_percentage=FALSE
where account.ndept_id =p_nDeptID
Group by dep.ndept_id,cac.nclient_cpc_mapping_id,client.sclient_cpc
,dep.sdept_name,dep.sclient_dept_id, dep.balternate_jointuse_percentage
UNION
SELECT Department_1.ndept_id, a_1.SumByCPC, clientcostpoolcodes.nclient_cpc_mapping_id, clientcostpoolcodes .sclient_cpc, Department_1.sdept_name, Department_1.sclient_dept_id , 'YES' AS sAlternateJointUsePercentage
FROM department AS Department_1 LEFT OUTER JOIN
mastercostpoolcodes RIGHT OUTER JOIN
clientcostpoolcodes RIGHT OUTER JOIN
(SELECT JointUseStatistics_1.nccp_code, SUM(JointUseStatistics_1.npercent) /
(SELECT SUM(jointusestatistics.npercent) AS SumByCPC
FROM jointusestatistics INNER JOIN
roomdepartmentmapping ON jointusestatistics.nroom_allocation_id = roomdepartmentmapping .nroom_allocation_id
WHERE (roomdepartmentmapping .ndept_id = Room_1.ndept_id)) * 100 AS SumByCPC,
Room_1.ndept_id
FROM jointusestatistics JointUseStatistics_1 INNER JOIN roomdepartmentmapping AS Room_1 ON JointUseStatistics_1.nroom_allocation_id = Room_1.nroom_allocation_id
GROUP BY JointUseStatistics_1.nccp_code, JointUseStatistics_1.npercent, Room_1.ndept_id) AS a_1 ON
clientcostpoolcodes .nclient_cpc_mapping_id = a_1.nccp_code ON mastercostpoolcodes .nmaster_cpc_id = clientcostpoolcodes .nmaster_cpc_id ON
Department_1.ndept_id = a_1.ndept_id
WHERE (Department_1.balternate_jointuse_percentage = 'TRUE')
AND (Department_1.ninst_id= p_nInstID)
)AS My
where (ndept_id= p_nDeptID )
ORDER BY My.sdept_name,My.CPCCODE ;
END;
$$ LANGUAGE plpgsql;
I think what you want is the first query to just retrieve the count, store that in your variable, then use that variable in the second query which is the actual source of the result of the function.
So the first query should not use return query but select .. into .. store put the result into the variable.
Then you can prefix the second query with return query to return its result:
CREATE OR REPLACE FUNCTION GetDeptListForViewModifyJointUsePercentages ( p_nInstID numeric,p_nDeptID numeric)
RETURNS Table(
res_ndept_id numeric,
res_salaryPercent character varying,
res_nclient_cpc_mapping_id numeric,
res_CPCCODE character varying,
res_sdept_name character varying,
res_sclient_dept_id character varying,
res_sAlternateJointUsePercentage character varying
)
AS $$
declare
v_AccountTotal numeric(18,2);
BEGIN
-- no RETURN query here!!
select SUM(CAST (coalesce(eam.npayroll_amt, null) AS numeric(18,2)))
into v_accounttotal --<<< store result in variable
FROM Account acct
INNER JOIN employeeaccountmapping eam
ON eam.nacct_id = acct.naccount_id
AND acct.ninst_id =p_nInstID
where acct.ndept_id = p_nDeptID;
-- this is the query that should be returned
RETURN QUERY
SELECT *
FROM (
select dep.ndept_id,
CASE WHEN v_AccountTotal = 0 THEN 0
ELSE Round(SUM(CAST(coalesce(eam.npayroll_amt, null) AS numeric(18,2)) * cac.npercentage_assigned/100) / v_AccountTotal *100,null)
END as salaryPercent,
cac.nclient_cpc_mapping_id,
client.sclient_cpc AS CPCCODE,
dep.sdept_name,
dep.sclient_dept_id,
'NO' AS sAlternateJointUsePercentage
FROM account
INNER JOIN employeeaccountmapping eam
ON eam.nacct_id = account .naccount_id AND account .ninst_id=p_nInstID
INNER JOIN accountcpcmapping acm
ON acm.naccount_cpc_mapping_id = account.naccount_cpc_mapping_id
INNER JOIN cpcaccountcpcmapping as cac
ON cac.naccount_cpc_mapping_id=acm.naccount_cpc_mapping_id
INNER JOIN clientcostpoolcodes as client
ON client.nclient_cpc_mapping_id=cac.nclient_cpc_mapping_id
INNER JOIN mastercostpoolcodes
ON mastercostpoolcodes .nmaster_cpc_id= client.nmaster_cpc_id
INNER JOIN department as dep
ON account.ndept_id=dep.ndept_id and dep.balternate_jointuse_percentage=FALSE
where account.ndept_id =p_nDeptID
Group by dep.ndept_id,cac.nclient_cpc_mapping_id,client.sclient_cpc
,dep.sdept_name,dep.sclient_dept_id, dep.balternate_jointuse_percentage
UNION
SELECT Department_1.ndept_id, a_1.SumByCPC, clientcostpoolcodes.nclient_cpc_mapping_id,
clientcostpoolcodes .sclient_cpc, Department_1.sdept_name, Department_1.sclient_dept_id,
'YES' AS sAlternateJointUsePercentage
FROM department AS Department_1
LEFT OUTER JOIN mastercostpoolcodes --<<< missing join condition !!
RIGHT OUTER JOIN clientcostpoolcodes --<<< missing join condition !!
RIGHT OUTER JOIN (
SELECT JointUseStatistics_1.nccp_code,
SUM(JointUseStatistics_1.npercent) /
(SELECT SUM(jointusestatistics.npercent) AS SumByCPC
FROM jointusestatistics
INNER JOIN roomdepartmentmapping ON jointusestatistics.nroom_allocation_id = roomdepartmentmapping .nroom_allocation_id
WHERE (roomdepartmentmapping .ndept_id = Room_1.ndept_id)) * 100 AS SumByCPC,
Room_1.ndept_id
FROM jointusestatistics JointUseStatistics_1
INNER JOIN roomdepartmentmapping AS Room_1 ON JointUseStatistics_1.nroom_allocation_id = Room_1.nroom_allocation_id
GROUP BY JointUseStatistics_1.nccp_code, JointUseStatistics_1.npercent, Room_1.ndept_id
) AS a_1 ON clientcostpoolcodes.nclient_cpc_mapping_id = a_1.nccp_code
ON mastercostpoolcodes.nmaster_cpc_id = clientcostpoolcodes.nmaster_cpc_id --<< that should be somewhere else
ON Department_1.ndept_id = a_1.ndept_id --<< ??????
WHERE (Department_1.balternate_jointuse_percentage = 'TRUE')
AND (Department_1.ninst_id= p_nInstID)
) AS My
where (ndept_id= p_nDeptID )
ORDER BY My.sdept_name,My.CPCCODE;
END;
$$ LANGUAGE plpgsql;
Note that there are several syntax errors in your second query because the join conditions are scattered around the query. I have tried to highlight them.
In Postgresql, function returns a single value. But in your example, you are trying to return multiple outputs in terms of number of rows and columns.
You can alternatively use a stored procedure and save the output in a temporary table. Later use that table for your use.
I want to create a function like below which inserts data as per the input given. But I keep on getting an error about undetermined dollar sign.
CREATE OR REPLACE FUNCTION test_generate
(
ref REFCURSOR,
_id INTEGER
)
RETURNS refcursor AS $$
DECLARE
BEGIN
DROP TABLE IF EXISTS test_1;
CREATE TEMP TABLE test_1
(
id int,
request_id int,
code text
);
IF _id IS NULL THEN
INSERT INTO test_1
SELECT
rd.id,
r.id,
rd.code
FROM
test_2 r
INNER JOIN
raw_table rd
ON
rd.test_2_id = r.id
LEFT JOIN
observe_test o
ON
o.raw_table_id = rd.id
WHERE o.id IS NULL
AND COALESCE(rd.processed, 0) = 0;
ELSE
INSERT INTO test_1
SELECT
rd.id,
r.id,
rd.code
FROM
test_2 r
INNER JOIN
raw_table rd
ON rd.test_2_id = r.id
WHERE r.id = _id;
END IF;
DROP TABLE IF EXISTS tmp_test_2_error;
CREATE TEMP TABLE tmp_test_2_error
(
raw_table_id int,
test_2_id int,
error text,
record_num int
);
INSERT INTO tmp_test_2_error
(
raw_table_id,
test_2_id,
error,
record_num
)
SELECT DISTINCT
test_1.id,
test_1.test_2_id,
'Error found ' || test_1.code,
0
FROM
test_1
WHERE 1 = 1
AND data_origin.id IS NULL;
INSERT INTO tmp_test_2_error
SELECT DISTINCT
test_1.id,
test_1.test_2_id,
'Error found ' || test_1.code,
0
FROM
test_1
INNER JOIN
data_origin
ON
data_origin.code = test_1.code
WHERE dop.id IS NULL;
DROP table IF EXISTS test_latest;
CREATE TEMP TABLE test_latest AS SELECT * FROM observe_test WHERE 1 = 2;
INSERT INTO test_latest
(
raw_table_id,
series_id,
timestamp
)
SELECT
test_1.id,
ds.id AS series_id,
now()
FROM
test_1
INNER JOIN data_origin ON data_origin.code = test_1.code
LEFT JOIN
observe_test o ON o.raw_table_id = test_1.id
WHERE o.id IS NULL;
CREATE TABLE latest_observe_test as Select * from test_latest where 1=0;
INSERT INTO latest_observe_test
(
raw_table_id,
series_id,
timestamp,
time
)
SELECT
t.id,
ds.id AS series_id,
now(),
t.time
FROM
test_latest t
WHERE t.series_id IS DISTINCT FROM observe_test.series_id;
DELETE FROM test_2_error re
USING t
WHERE t.test_2_id = re.test_2_id;
INSERT INTO test_2_error (test_2_id, error, record_num)
SELECT DISTINCT test_2_id, error, record_num FROM tmp_test_2_error ORDER BY error;
UPDATE raw_table AS rd1
SET processed = case WHEN tre.raw_table_id IS null THEN 2 ELSE 1 END
FROM test_1 tr
LEFT JOIN
tmp_test_2_error tre ON tre.raw_table_id = tr.id
WHERE rd1.id = tr.id;
OPEN ref FOR
SELECT 1;
RETURN ref;
OPEN ref for
SELECT o.* from observe_test o
;
RETURN ref;
OPEN ref FOR
SELECT
rd.id,
ds.id AS series_id,
now() AS timestamp,
rd.time
FROM test_2 r
INNER JOIN raw_table rd ON rd.test_2_id = r.id
INNER JOIN data_origin ON data_origin.code = rd.code
WHERE o.id IS NULL AND r.id = _id;
RETURN ref;
END;
$$ LANGUAGE plpgsql VOLATILE COST 100;
I am not able to run this procedure.
Can you please help me where I have done wrong?
I am using squirrel and face the same question as you.
until I found that:
-- Note that if you want to create the function under Squirrel SQL,
-- you must go to Sessions->Session Properties
-- then SQL tab and change the Statement Separator from ';' to something else
-- (for intance //). Otherwise Squirrel SQL sends one piece to the server
-- that stops at the first encountered ';', and the server cannot make
-- sense of it. With the separator changed as suggested, you type everything
-- as above and end with
-- ...
-- end;
-- $$ language plpgsql
-- //
--
-- You can then restore the default separator, or use the new one for
-- all queries ...
--
WITH temp AS (select * from t1 where c1 = 'string1')
select 'string1' as col1, t2.col2, temp.col3 from t2 inner join temp on t2.c2 = temp.c2 where t2.some_col like 'string1%'
union
WITH temp AS (select * from t1 where c1 = 'string2')
select 'string2' as col1, t2.col2, temp.col3 from t2 inner join temp on t2.c2 = temp.c2 where t2.some_col like 'string2%'
...
Above is just an example of a PostgreSQL query I am trying to run. It's a union of two completely similar queries. They only use different values for matching string1 and string2.
I have about 20 such queries that I want to do a union on. They only differ by the variable I want to use for comparison such as string1
How can I use such array of values ['string1', 'string2', 'string3', .., 'string20'], run a query on each variable from this array and union them?
What about a old fashioned plpgsql?
CREATE OR REPLACE FUNCTION get_all_foo(arr varchar[]) RETURNS TABLE (col1 TEXT, col2 TEXT, col3 TEXT) AS
$BODY$
DECLARE
arr_value varchar;
generated_query varchar := '';
array_index smallint := 1;
array_length smallint;
BEGIN
array_length := array_length(arr, 1);
FOREACH arr_value IN ARRAY arr LOOP
generated_query := generated_query || format(' (WITH temp AS (select * from t1 where c1 = %L) '
'select %L as col1, t2.col2, temp.col3 from t2 inner join temp on t2.c2 = temp.c2 where t2.some_col like ''%s%%'')', arr_value, arr_value, arr_value);
IF array_index < array_length THEN
generated_query := generated_query || ' UNION ';
END IF;
array_index := array_index+1;
END LOOP;
RAISE DEBUG 'Generated query: %', generated_query;
RETURN QUERY EXECUTE generated_query;
END
$BODY$
LANGUAGE plpgsql;
--Uncomment to see generated query
--SET client_min_messages = DEBUG;
SELECT * FROM get_all_foo(array['string1', 'string2', 'string3', 'string4', 'string5']);
select c1 as col1, t2.col2, temp.col3
from
(select col2, c2 from t2 where
some_col like 'string1%' or some_col like 'string2%' or <other strings in the similar fashion>) t2
inner join
(select c1,c2,col3 from t1 where c1 in ('string1', 'string2', <other strings in the similar fashion>)) temp
on t2.c2 = temp.c2;
WITH temp AS (
select *
from t1
where c1 = any(array['string1','string2','string3']))
select distinct
temp.c1 as col1, t2.col2, temp.col3
from t2 inner join
temp on (t2.c2 = temp.c2 and t2.some_col like temp.c1||'%')