DB2 With in clause, cache variable - db2

According to the example of Generate aggregated Json data from Json string in java, I want to cache the result length in a variable within a function
DECLARE result CLOB;
DECLARE leng INT;
WITH BASE AS (
select id, item,
JSON_OBJECT('item' value item,
'itemScore' value itemScore,
'stage' value stage,
'reco' VALUE JSON_OBJECT('product' value product,
'url' value url ,
'score' value score
FORMAT JSON )
FORMAT JSON ABSENT ON NULL
RETURNING VARCHAR(200) FORMAT JSON) ITEM_JSON
FROM PROD_T ),
SIZE AS (SELECT COUNT(*) AS SIZ INTO leng FROM BASE),--not working
PROD_OBJS AS (
SELECT JSON_OBJECT ( KEY 'id' VALUE ID ,
KEY 'itens' VALUE
JSON_ARRAY ( LISTAGG( ITEM_JSON , ', ') WITHIN GROUP (ORDER BY ITEM) FORMAT JSON )
FORMAT JSON ) json_objects
FROM BASE GROUP BY ID )
SELECT JSON_ARRAY (select json_objects FROM PROD_OBJS format json) INTO result FROM SYSIBM.SYSDUMMY1;
I tried this one, see the line above, but it is not working
SIZE AS (SELECT COUNT(*) AS SIZ INTO leng FROM BASE)

A single INTO is allowed in a SELECT statement only.
Run it as is to check and uncomment the commented out block in your function (removing the VALUES block obviously to work with your real PROD_T table).
WITH BASE AS (
select id, item,
JSON_OBJECT('item' value item,
'itemScore' value itemScore,
'stage' value stage,
'reco' VALUE JSON_OBJECT('product' value product,
'url' value url ,
'score' value score
)
ABSENT ON NULL
RETURNING VARCHAR(200) FORMAT JSON) ITEM_JSON
FROM
(
VALUES
('id1', 'item1', 'itemScore1', 'stage1', 'product1', 'url1', 'score1')
, ('id2', 'item2', 'itemScore2', 'stage2', 'product2', 'url2', 'score2')
)
PROD_T (id, item, itemScore, stage, product, url, score)
),
PROD_OBJS AS (
SELECT JSON_OBJECT ( KEY 'id' VALUE ID ,
KEY 'itens' VALUE
JSON_ARRAY ( LISTAGG( ITEM_JSON , ', ') WITHIN GROUP (ORDER BY ITEM) FORMAT JSON )
FORMAT JSON ) json_objects
FROM BASE GROUP BY ID )
SELECT
JSON_ARRAY (select json_objects FROM PROD_OBJS format json)
, (SELECT COUNT(*) FROM BASE)
--INTO result, leng
FROM SYSIBM.SYSDUMMY1

Related

Postgres Jsonb aggregation

I am trying to achieve following (Result Required) output from POSTGRES jsonb columns, but not getting desired result using "jsonb_agg" function.
I went through this postgres document https://www.postgresql.org/docs/12/functions-json.html, but no luck here.
Also am not that good in json data in postgres, so please suggest good resource for json formatting related stuff for postgres.
City
JColA
JColB
NY
[{"id":"ID1","name":"ID1_NAME","type":"ID1_TYPE","amount":20.12,"full_name":null},{"id":"ID2","name":"ID2_NAME","type":"ID2_TYPE","amount":11.55,"full_name":null},{"id":"ID1","name":"ID1_NAME","type":"ID1_TYPE","amount":5.45,"full_name":null}]
[{"key":"key1","value":"1"},{"key":"key2","value":"2"},{"key":"key3","value":"3"}]
DC
[{"id":"ID1","name":"ID1_NAME","type":"ID1_TYPE","amount":1.5,"full_name":null},{"id":"ID3","name":"ID3_NAME","type":"ID3_TYPE","amount":1.2,"full_name":null},{"id":"ID4","name":"ID4_NAME","type":"ID4_TYPE","amount":1,"full_name":null}]
[{"key":"key1","value":"1"},{"key":"key1","value":"2"},{"key":"key1","value":"3"}]
DL
[{"id":"ID4","name":"ID4_NAME","type":"ID4_TYPE","amount":1.5,"full_name":null},{"id":"ID2","name":"ID2_NAME","type":"ID2_TYPE","amount":1.2,"full_name":null},{"id":"ID4","name":"ID4_NAME","type":"ID4_TYPE","amount":1,"full_name":null}]
[{"key":"key1","value":"2"},{"key":"key2","value":"2"},{"key":"key3","value":"4"}]
NY
[{"id":"ID1","name":"ID1_NAME","type":"ID1_TYPE","amount":4.5,"full_name":null},{"id":"ID2","name":"ID2_NAME","type":"ID2_TYPE","amount":2.2,"full_name":null},{"id":"ID4","name":"ID4_NAME","type":"ID4_TYPE","amount":6,"full_name":null}]
[{"key":"key4","value":"2"},{"key":"key2","value":"5"},{"key":"key2","value":"4"}]
DC
[{"id":"ID3","name":"ID3_NAME","type":"ID3_TYPE","amount":2.5,"full_name":null},{"id":"ID3","name":"ID3_NAME","type":"ID3_TYPE","amount":2.2,"full_name":null},{"id":"ID4","name":"ID4_NAME","type":"ID4_TYPE","amount":2,"full_name":null}]
[{"key":"key1","value":"2"},{"key":"key2","value":"2"},{"key":"key3","value":"4"}]
Required Result
City
AggJSonColA
AggJsonColB
NY
[{"id":"ID1","name":"ID1_NAME","type":"ID1_TYPE","amount":30.07,"full_name":null},{"id":"ID2","name":"ID2_NAME","type":"ID2_TYPE","amount":13.75,"full_name":null},{"id":"ID4","name":"ID4_NAME","type":"ID4_TYPE","amount":6,"full_name":null}]
[{"key":"key1","value":"1"},{"key":"key2","value":"11"},{"key":"key3","value":"3"}, {"key":"key4","value":"2"}]
DC
[{"id":"ID1","name":"ID1_NAME","type":"ID1_TYPE","amount":1.5,"full_name":null},{"id":"ID3","name":"ID3_NAME","type":"ID3_TYPE","amount":5.9,"full_name":null},{"id":"ID4","name":"ID4_NAME","type":"ID4_TYPE","amount":3,"full_name":null}]
[{"key":"key1","value":"8"},{"key":"key2","value":"2"},{"key":"key3","value":"4"}]
DL
[{"id":"ID4","name":"ID4_NAME","type":"ID4_TYPE","amount":1.5,"full_name":null},{"id":"ID2","name":"ID2_NAME","type":"ID2_TYPE","amount":1.2,"full_name":null},{"id":"ID4","name":"ID4_NAME","type":"ID4_TYPE","amount":1,"full_name":null}]
[{"key":"key1","value":"2"},{"key":"key2","value":"2"},{"key":"key3","value":"4"}]
You need to break out the arrays with jsonb_to_recordset, rebuild the objects using jsonb_build_object, and aggregate them back up with jsonb_agg
SELECT
A.City,
A.JColA,
B.JColB
FROM (
SELECT
City,
jsonb_agg(JColA) AS JColA
FROM (
SELECT
t.City,
json_build_object(
'id', id,
'name', name,
'type', type,
'amount', SUM(amount),
'full_name', full_name
) AS JColA
FROM YourTable t,
LATERAL jsonb_to_recordset(t.JColA)
AS arr(id varchar(10), name varchar(100), type varchar(100), amount decimal (18,2), full_name varchar(100))
GROUP BY
t.City, arr.id, arr.name, arr.type, arr.full_name
) A
GROUP BY
City
) A
JOIN (
SELECT
City,
jsonb_agg(JColB) AS JColB
FROM (
SELECT
t.City,
json_build_object(
'key', "key",
'value', SUM(value)
) AS JColB
FROM YourTable t,
LATERAL jsonb_to_recordset(t.JColB)
AS arr("key" varchar(10), value int)
GROUP BY
t.City, arr."key"
) B
GROUP BY
City
) B ON B.City = A.City;
I feel it's easier to requery the original table again, however if you want to avoid that, you could first aggregate all the arrays together by City, break them back out and re-aggregate.
SELECT
t.City,
(
SELECT
jsonb_agg(JColA)
FROM (
SELECT
json_build_object(
'id', id,
'name', name,
'type', type,
'amount', SUM(amount),
'full_name', full_name
) AS JColA
FROM jsonb_array_elements(t.JColA) AS outerArr,
LATERAL jsonb_to_recordset(outerArr)
AS arr(id varchar(10), name varchar(100), type varchar(100), amount decimal (18,2), full_name varchar(100))
GROUP BY
arr.id, arr.name, arr.type, arr.full_name
) A
) AS JColA,
(
SELECT
jsonb_agg(JColB)
FROM (
SELECT
json_build_object(
'key', "key",
'value', SUM(arr.value)
) AS JColB
FROM jsonb_array_elements(t.JColB) AS outerArr,
LATERAL jsonb_to_recordset(outerArr)
AS arr("key" varchar(10), value int)
GROUP BY
arr."key"
) B
) AS JColB
FROM (
SELECT
t.City,
jsonb_agg(JColA) AS JColA,
jsonb_agg(JColB) AS JColB
FROM YourTable t
GROUP BY
t.City
) t;
db<>fiddle

How to order by result set in union query in T-SQL

I want to use order by clause in my last sql query and I have more than 3 union queries. I do not want to order the top 2 union query but I want to use order by clause in my last sql statement.
Currently, getting error
ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.
select 'Total Number of pat' Name, convert(varchar(20), count(id)) Number from table2 where id = 5
union
select 'Total Number of Doc' Name, convert(varchar(20), count(id)) Number from table3
union
select x.usertype, count(distinct userid) cnt
from [dbo].table1 t
cross apply (values (
case when t.userid like '%[0-9][0-9[0-9]' then 'transition' else 'non transition' end,
t.userid
)) x(usertype, userid)
where t.date >= dateadd(day,-7, getdate())
group by x.usertype
order by usertype desc
order by is sorting the result of the unions all together however you can introduce a orderIndex column for imlementing the right ordering.
Here the sample:
I've tried to build sample data in the following code.
create table table1(
userid varchar(100),
usertype varchar(100),
date date
)
insert into table1(userid, date) values ('Einsmayr', '2020-10-27')
insert into table1(userid, date) values ('Eins123', '2020-10-27')
insert into table1(userid, date) values ('Einschmid', '2020-10-27')
insert into table1(userid, date) values ('Einshuber', '2020-10-27')
insert into table1(userid, date) values ('Einsreitmayr', '2020-10-27')
create table table2 (
Name varchar(100),
id int
)
insert into table2(Name, id) values('Zweirich', 5)
insert into table2(Name, id) values('Zweifel', 6)
create table table3 (
Name varchar(100),
id int
)
insert into table3(Name, id) values('Dreisinger', 17)
insert into table3(Name, id) values('Dreibert', 18)
This allows the following queries:
select usertype, Number
from (
select 'Total Number of pat' usertype, convert(varchar(20), count(id)) Number, 1 orderIndex from table2 where id = 5
union
select 'Total Number of Doc' Name, convert(varchar(20), count(id)) Number, 2 orderIndex from table3
union
select usertype, count(distinct userid) Number, 3 orderIndex
from (
select userid, case when userid like '%[0-9][0-9[0-9]' then 'transition' else 'non transition' end usertype
from table1
where date >= dateadd(day,-7, getdate())
) x
group by x.usertype
) y
order by y.orderIndex, y.usertype
Find the solution here: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=ac396c48f5dbcb4a53ad40fac70e9236

DB2 XML Select multiple rows in Single statements

In My code,
SELECT X.DEP_ID
FROM (SELECT XMLPARSE (DOCUMENT '<root><DEP_ID>1000000004</DEP_ID><DEP_ID>1000000005</DEP_ID></root>') AS ELEMENT_VALUE
FROM SYSIBM.SYSDUMMY1) AS A,
XMLTABLE (
'$d/root'
PASSING Element_value AS "d"
COLUMNS
DEP_ID VARCHAR (10) PATH 'DEP_ID'
) AS X;
Need as result of:
DEP_ID
1000000004
1000000005
If its single values means it working that means only one DEP_ID in xml.
But Multiple return means it will show error.
How to get the output as like above in db2.
Wrong row-xquery-expression-constant.
Try this:
SELECT X.DEP_ID
FROM
(
SELECT XMLPARSE (DOCUMENT '<root><DEP_ID>1000000004</DEP_ID><DEP_ID>1000000005</DEP_ID></root>') AS ELEMENT_VALUE
FROM SYSIBM.SYSDUMMY1
) AS A
, XMLTABLE
(
'$d/root/DEP_ID' PASSING Element_value AS "d"
COLUMNS
DEP_ID VARCHAR (10) PATH '.'
) AS X;

Insert where not exists, else return row [duplicate]

I have a simple table in PostgreSQL that has three columns:
id serial primary key
key varchar
value varchar
I have already seen this question here on SO: Insert, on duplicate update in PostgreSQL? but I'm wondering just how to get the id if it exists, instead of updating. If the standard practice is to always either "insert" or "update if exists", why is that? Is the cost of doing a SELECT (LIMIT 1) greater than doing an UPDATE?
I have the following code
INSERT INTO tag
("key", "value")
SELECT 'key1', 'value1'
WHERE
NOT EXISTS (
SELECT id,"key","value" FROM tag WHERE key = 'key1' AND value = 'value1'
);
which works in the sense that it doesn't insert if exists, but I'd like to get the id. Is there a "RETURNING id" clause or something similar that I could tap in there?
Yes there is returning
INSERT INTO tag ("key", "value")
SELECT 'key1', 'value1'
WHERE NOT EXISTS (
SELECT id, "key", "value"
FROM node_tag
WHERE key = 'key1' AND value = 'value1'
)
returning id, "key", "value"
To return the row if it already exists
with s as (
select id, "key", "value"
from tag
where key = 'key1' and value = 'value1'
), i as (
insert into tag ("key", "value")
select 'key1', 'value1'
where not exists (select 1 from s)
returning id, "key", "value"
)
select id, "key", "value"
from i
union all
select id, "key", "value"
from s
If the row does not exist it will return the inserted one else the existing one.
BTW, if the pair "key"/"value" makes it unique then it is the primary key, and there is no need for an id column. Unless one or both of the "key"/"value" pair can be null.
with vals as (
select 'key5' as key, 'value2' as value
)
insert into Test1 (key, value)
select v.key, v.value
from vals as v
where not exists (select * from Test1 as t where t.key = v.key and t.value = v.value)
returning id
sql fiddle demo
And you can store value returned to variables in form of ... RETURNING field1, field2,... INTO var1, var2,...
RETURNING will normally return a query which would return Error 'query has no destination for result data' if you call it in plpgsql without using its returned result set.

Insert if not exists, else return id in postgresql

I have a simple table in PostgreSQL that has three columns:
id serial primary key
key varchar
value varchar
I have already seen this question here on SO: Insert, on duplicate update in PostgreSQL? but I'm wondering just how to get the id if it exists, instead of updating. If the standard practice is to always either "insert" or "update if exists", why is that? Is the cost of doing a SELECT (LIMIT 1) greater than doing an UPDATE?
I have the following code
INSERT INTO tag
("key", "value")
SELECT 'key1', 'value1'
WHERE
NOT EXISTS (
SELECT id,"key","value" FROM tag WHERE key = 'key1' AND value = 'value1'
);
which works in the sense that it doesn't insert if exists, but I'd like to get the id. Is there a "RETURNING id" clause or something similar that I could tap in there?
Yes there is returning
INSERT INTO tag ("key", "value")
SELECT 'key1', 'value1'
WHERE NOT EXISTS (
SELECT id, "key", "value"
FROM node_tag
WHERE key = 'key1' AND value = 'value1'
)
returning id, "key", "value"
To return the row if it already exists
with s as (
select id, "key", "value"
from tag
where key = 'key1' and value = 'value1'
), i as (
insert into tag ("key", "value")
select 'key1', 'value1'
where not exists (select 1 from s)
returning id, "key", "value"
)
select id, "key", "value"
from i
union all
select id, "key", "value"
from s
If the row does not exist it will return the inserted one else the existing one.
BTW, if the pair "key"/"value" makes it unique then it is the primary key, and there is no need for an id column. Unless one or both of the "key"/"value" pair can be null.
with vals as (
select 'key5' as key, 'value2' as value
)
insert into Test1 (key, value)
select v.key, v.value
from vals as v
where not exists (select * from Test1 as t where t.key = v.key and t.value = v.value)
returning id
sql fiddle demo
And you can store value returned to variables in form of ... RETURNING field1, field2,... INTO var1, var2,...
RETURNING will normally return a query which would return Error 'query has no destination for result data' if you call it in plpgsql without using its returned result set.