Update nested list of tables in KDB table - kdb

I have the below table where I am trying to update the empty schemas of a nested list of table and populate them with results in t1
t:flip (`userName`nestedList)!(("user1";"user2";"user3";"user4");(flip (`col1`col2`col3`col4`col5`col6`col7)!(`symbol$();();();();();();());flip (`col1`col2`col3`col4`col5`col6`col7)!(enlist `XXX_XXX;enlist 0b;enlist 2000j;enlist -1j;enlist 1b;enlist 0b;enlist 0b);flip (`col1`col2`col3`col4`col5`col6`col7)!(`symbol$();();();();();();());flip (`col1`col2`col3`col4`col5`col6`col7)!(enlist `XXX_XXX;enlist 0b;enlist 2000j;enlist -1j;enlist 1b;enlist 0b;enlist 0b)))
Desired result is t1
t1:flip (`userName`nestedList)!(("user1";"user2";"user3";"user4");(flip (`col1`col2`col3`col4`col5`col6`col7)!(enlist `;enlist 0b;enlist 0;enlist 0;enlist 0b;enlist 0b;enlist 0b);flip (`col1`col2`col3`col4`col5`col6`col7)!(enlist `XXX_XXX;enlist 0b;enlist 2000j;enlist -1j;enlist 1b;enlist 0b;enlist 0b);flip (`col1`col2`col3`col4`col5`col6`col7)!(enlist `;enlist 0b;enlist 0;enlist 0;enlist 0b;enlist 0b;enlist 0b);flip (`col1`col2`col3`col4`col5`col6`col7)!(enlist `XXX_XXX;enlist 0b;enlist 2000j;enlist -1j;enlist 1b;enlist 0b;enlist 0b)))
//trying to update the t so the count of running below is 4 instead of 2
raze exec nestedList from t //count=2
raze exec nestedList from t1 //count=4
Thanks for your help!

Here's one way to do it.
q)update nestedList:count[i]#enlist flip`col1`col2`col3`col4`col5`col6`col7!1#'(`;0b;0;0;0b;0b;0b)from t where userName in("user1";"user3")
userName nestedList
-----------------------------------------------------------------------------------
"user1" +`col1`col2`col3`col4`col5`col6`col7!(,`;,0b;,0;,0;,0b;,0b;,0b)
"user2" +`col1`col2`col3`col4`col5`col6`col7!(,`XXX_XXX;,0b;,2000;,-1;,1b;,0b;,0b)
"user3" +`col1`col2`col3`col4`col5`col6`col7!(,`;,0b;,0;,0;,0b;,0b;,0b)
"user4" +`col1`col2`col3`col4`col5`col6`col7!(,`XXX_XXX;,0b;,2000;,-1;,1b;,0b;,0b)
q)t1~update nestedList:count[i]#enlist flip`col1`col2`col3`col4`col5`col6`col7!1#'(`;0b;0;0;0b;0b;0b)from t where userName in("user1";"user3")
1b
q)count raze exec nestedList from update nestedList:count[i]#enlist flip`col1`col2`col3`col4`col5`col6`col7!1#'(`;0b;0;0;0b;0b;0b)from t where userName in("user1";"user3")
4
If you need the where clause to consider the nestedList column instead, you could use
q)t1~update nestedList:count[i]#enlist flip`col1`col2`col3`col4`col5`col6`col7!1#'(`;0b;0;0;0b;0b;0b)from t where not count each nestedList
1b

Related

Get matching elements from an array comparison

I'm attempting to get matching elements regarding two arrays. I need to select them, so it essentially goes as follows
Contstraints:
Using Postgres 12, with no plugins.
String arrays, not int.
SQL I've come up with:
SELECT
elb.1,
elb.2,
esp.1,
esp.2
FROM
schema.table1 as esp
JOIN schema.table2 elb ON (elb.1 = esp.1)
WHERE
(esp.3 && ('{DHE:false, DHE:true, CAM:true}'::text[]))
Let's assume esp.3 ==
'{
BHE:false,
DHE:true,
CMD:true,
}'
What is the cleanest way to get that matching value DHE:true from these two arrays? I can't really alter the format of what i have here by much, so no functions etc.
I was really hoping to have something like:
SELECT
elb.1,
elb.2,
esp.1,
esp.2,
diff
FROM
schema.table1 as esp
JOIN schema.table2 elb ON (elb.1 = esp.1)
WHERE
select((esp.3 in any('{DHE:false, DHE:true, CAM:true}'::text[]))) as diff;
But i couldn't find any solution or variation on that. Any help is greatly appreciated!
any only returns true or false so it can stop looking once it matches.
You can use the technique from this answer to get the intersection of two text arrays.
SELECT
elb.1,
elb.2,
esp.1,
esp.2,
ARRAY(
SELECT *
FROM UNNEST( esp.3 )
WHERE UNNEST = ANY('{DHE:false, DHE:true, CAM:true}'::text[])
) as diff
FROM
schema.table1 as esp
JOIN schema.table2 elb ON (elb.1 = esp.1)
WHERE
(esp.3 && ('{DHE:false, DHE:true, CAM:true}'::text[]))
You can DRY it up with a CTE to first take the diff, then check it.
with esp as (
select
1,
2,
ARRAY(
SELECT *
FROM UNNEST( 3 )
WHERE UNNEST = ANY('{DHE:false, DHE:true, CAM:true}'::text[])
) as diff
from schema.table1
)
select
elb.1,
elb.2,
esp.1,
esp.2,
esp.diff
from
schema.table2 elb
join esp on (elb.1 = esp.1)
where cardinality(esp.diff) != 0;

How to use a recursive query in a subquery in PostgreSQL

I created a recursive query that returns me a string of the productcategory history (typical parent-child relation:
with recursive productCategoryHierarchy as (
--start with the "anchor" row
select
1 as "level",
pg1.id,
pg1.title,
pg1.parentproductgroup_id
from product_group pg1
where
pg1.id = '17e949b6-85b3-4c87-8f76-ad1e61ea01e1' --parameterize me
union all
-- Get child nodes
select
pch.level +1 as "level",
pg2.id,
pg2.title,
pg2.parentproductgroup_id
from product_group pg2
join productCategoryHierarchy pch on pch.parentproductgroup_id = pg2.id
)
-- Get hierarchy as string
select
CONCAT('',string_agg(productCategoryHierarchy.title, ' > '),'')
from productCategoryHierarchy;
Now I want to use this result in another query as a subquery so that I can use the created string as an attribute in the parent query. Is that possible in Postgres or is there another solution to get a hierarchical tree as string in an attribute?
Are you looking for something like this?
with recursive productcategoryhierarchy as (
...
), aggregated_values as (
select string_agg(productCategoryHierarchy.title, ' > ') as all_titles
from productCategoryHierarchy
)
select ..., (select all_titles from aggregated_values) as all_titles
from ... your main query goes here ..

Update jsonb set new value select from the same table

i have a table foo:
id | items
---+--------------------------------
1 |{"item_1": {"status": "status_1"}}
2 |{"item_2": {"status": "status_2"}}
...
I need to update all rows in column items which is a jsonb and set after {"status": "status"} new values ("new_value": "new_value") and after update the result must look like this:
id | items
---+------------------------------------------------------------
1 |{"item_1": {"status": "status_1", "new_value": "new_value"}}
2 |{"item_2": {"status": "status_2", "new_value": "new_value"}}
...
i've tried to do this:
WITH result AS (
INSERT INTO foo (id, items)
SELECT id, options || newvalue as res
FROM foo AS bar,
jsonb_each(bar.items::jsonb) AS item,
to_jsonb(item.value) AS options,
jsonb_build_object('new_value', 'new_value') as newvalue
WHERE id IN ('1', '2'...)
ON CONFLICT (id)
DO UPDATE
SET items = foo.items || Excluded.items::jsonb RETURNING *)
SELECT item.key AS itemkey
FROM result AS res,
jsonb_each(res.items) AS item,
to_jsonb(item.value) AS options;
but when i run this script the postgres shows this error message:
on conflict do update command cannot affect row a second time postgres
i dont understand what am i doing wrong?
UPDATE#1
Postgres version 9.6
table foo id = TEXT UNIQUE NOT NULL
about why INSERT but not just UPDATE? the answer is this is my mistake first mistake.
after some reading postgres functions finally i find out:
UPDATE foo as t
SET items = result.new_value
FROM (SELECT st.id, new_value
FROM foo AS st
CROSS JOIN LATERAL (
SELECT jsonb_object_agg(the_key, the_value || '{"new_value": "some_new_value"}'::jsonb) AS new_value
FROM jsonb_each(st.items) AS x(the_key, the_value)
LIMIT 1) AS n) AS result
WHERE result.id = t.id;

Query returning different number of rows, results in crosstab error

I get this error with my query, but I can't figure out what is wrong with it:
Query-specified return tuple has 135 columns but crosstab returns 295.
And here's my query: (The part highlighted in bold returns same number of rows when run separately in pgAdmin.)
SELECT X.*, pi.productcode, pi.productitemdesc, pi.retailsalesprice, cat.productcategorydesc FROM (
SELECT * FROM crosstab (
'SELECT a.productitem AS productitemid, l.locationcode, (CASE WHEN SUM(a.netamount) IS NOT NULL THEN SUM(a.netamount) ELSE 0 END) || ''#'' || (CASE WHEN SUM(a.quantity) IS NOT NULL THEN SUM(a.quantity) ELSE 0 END) AS sales_qty FROM invoiceitem a INNER JOIN invoiceinfo b ON a.invoice = b.invoiceid INNER JOIN locationinfo l ON b.location = l.locationid WHERE b.status !=2 AND l.locationtype = 1 AND l.status = 1 AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')>=''2018-03-01'' AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')<=''2018-03-03'' GROUP BY a.productitem, l.locationcode ORDER BY a.productitem',
'SELECT l.locationcode FROM locationinfo l INNER JOIN invoiceinfo b ON b.location = l.locationid
WHERE b.status !=2 AND l.locationtype = 1 AND l.status = 1 AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')>=''2018-03-01'' AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')<=''2018-03-03'' GROUP BY l.locationcode order by l.locationcode')
AS (productitemid int, "0007" text,"BE101" text,"BE1013" text,"BE1014" text,"BE102" text,"BE103" text,"BE1034" text,"BE104" text,"BE1040" text,"BE1043" text,"BE1044" text,"BE1045" text,"BE1046" text,"BE105" text,"BE106" text,"BE107" text,"BE108" text,"BE109" text,"BE110" text,"BE111" text,"BE112" text,"BE123" text,"BE1265" text,"BE1266" text,"BE1271" text,"BE1272" text,"BE1273" text,"BE1274" text,"BE1279" text,"BE1280" text,"BE1281" text,"BE1282" text,"BE1351" text,"BE1400" text,"BE1401" text,"BE1404" text,"BE141" text,"BE142" text,"BE193" text,"BE194" text,"BE2125" text,"BE2126" text,"BE2127" text,"BE2128" text,"BE3001" text,"BE3002" text,"BE3005" text,"BE3006" text,"BE3009" text,"BE3010" text,"BE3031" text,"BE3032" text,"BE3121" text,"BE3122" text,"BE3123" text,"BE3124" text,"BE3127" text,"BE3128" text,"BE3131" text,"BE3132" text,"BE3203" text,"BE3204" text,"BE325" text,"BE3253" text,"BE3254" text,"BE326" text,"BE332" text,"BE3503" text,"BE3504" text,"BE355" text,"BE356" text,"BE365" text,"BE366" text,"BE381" text,"BE382" text,"BE383" text,"BE384" text,"BE400" text,"BE401" text,"BE402" text,"BE403" text,"BE405" text,"BE406" text,"BE408" text,"BE409" text,"BE411" text,"BE412" text,"BE4311" text,"BE4316" text,"BE4401" text,"BE4402" text,"BE4521" text,"BE4522" text,"BE4551" text,"BE4552" text,"BE470" text,"BE473" text,"BE475" text,"BE481" text,"BE482" text,"BE601" text,"BE604" text,"BE609" text,"BE610" text,"BE7040" text,"BE7043" text,"BE7045" text,"BE7046" text,"BE7048" text,"BE7049" text,"BE708" text,"BE7111" text,"BE7112" text,"BE7127" text,"BE7128" text,"BE7217" text,"BE7218" text,"BE7307" text,"BE7308" text,"BE7351" text,"BE7352" text,"BE801" text,"BE802" text,"BE803" text,"BE804" text,"BE831" text,"BE832" text,"BE860" text,"BE861" text,"BE862" text,"BE863" text,"BE865" text,"BE981" text,"BE982" text
)) X
LEFT JOIN productitem pi ON X.productitemid = pi.productitemid
LEFT JOIN productcategory cat ON pi.productcategory = cat.productcategoryid
The bold part of
productitemid int, "0007" text,"BE101" text,"BE1013" text,"BE1014" text,"BE102" text,"BE103" text,"BE1034" text,"BE104" text,"BE1040" text,"BE1043" text,"BE1044" text,"BE1045" text,"BE1046" text,"BE105" text,"BE106" text,"BE107" text,"BE108" text,"BE109" text,"BE110" text,"BE111" text,"BE112" text,"BE123" text,"BE1265" text,"BE1266" text,"BE1271" text,"BE1272" text,"BE1273" text,"BE1274" text,"BE1279" text,"BE1280" text,"BE1281" text,"BE1282" text,"BE1351" text,"BE1400" text,"BE1401" text,"BE1404" text,"BE141" text,"BE142" text,"BE193" text,"BE194" text,"BE2125" text,"BE2126" text,"BE2127" text,"BE2128" text,"BE3001" text,"BE3002" text,"BE3005" text,"BE3006" text,"BE3009" text,"BE3010" text,"BE3031" text,"BE3032" text,"BE3121" text,"BE3122" text,"BE3123" text,"BE3124" text,"BE3127" text,"BE3128" text,"BE3131" text,"BE3132" text,"BE3203" text,"BE3204" text,"BE325" text,"BE3253" text,"BE3254" text,"BE326" text,"BE332" text,"BE3503" text,"BE3504" text,"BE355" text,"BE356" text,"BE365" text,"BE366" text,"BE381" text,"BE382" text,"BE383" text,"BE384" text,"BE400" text,"BE401" text,"BE402" text,"BE403" text,"BE405" text,"BE406" text,"BE408" text,"BE409" text,"BE411" text,"BE412" text,"BE4311" text,"BE4316" text,"BE4401" text,"BE4402" text,"BE4521" text,"BE4522" text,"BE4551" text,"BE4552" text,"BE470" text,"BE473" text,"BE475" text,"BE481" text,"BE482" text,"BE601" text,"BE604" text,"BE609" text,"BE610" text,"BE7040" text,"BE7043" text,"BE7045" text,"BE7046" text,"BE7048" text,"BE7049" text,"BE708" text,"BE7111" text,"BE7112" text,"BE7127" text,"BE7128" text,"BE7217" text,"BE7218" text,"BE7307" text,"BE7308" text,"BE7351" text,"BE7352" text,"BE801" text,"BE802" text,"BE803" text,"BE804" text,"BE831" text,"BE832" text,"BE860" text,"BE861" text,"BE862" text,"BE863" text,"BE865" text,"BE981" text,"BE982" text
AND
SELECT l.locationcode FROM locationinfo l INNER JOIN invoiceinfo b ON b.location = l.locationid
WHERE b.status !=2 AND l.locationtype = 1 AND l.status = 1 AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')>=''2018-03-01'' AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')<=''2018-03-03'' GROUP BY l.locationcode order by l.locationcode
When run seperately, I get 295 results which is correct. However putting it together in the whole query gets the error.
The manual:
The remaining output columns must have the type of the last column of the source_sql query's result, and there must be exactly as many of them as there are rows in the category_sql query's result.
crosstab(text, text) with a dynamic (!) SELECT query as 2nd parameter is very error prone, since the output column list is static. You should also generate the output column list dynamically. Example:
Dynamic alternative to pivot with CASE and GROUP BY
That aside, the different number of rows returned from the same query, may very well be due to a different timezone setting in the two different sessions.
You have the expression TO_CHAR(b.invoicedate, 'YYYY-MM-DD') in your predicates. If b.invoicedate is type timestamptz the result depends on the timezone setting. Consider:
SET timezone = '+10';
SELECT TO_CHAR(timestamptz '2018-04-07 23:30+0', 'YYYY-MM-DD');
to_char
----------
2018-04-08
SET timezone = '-10';
SELECT TO_CHAR(timestamptz '2018-04-07 23:30+0', 'YYYY-MM-DD');
to_char
----------
2018-04-07
Solution
To remove the dependency on the timezone setting, use absolute values.
to_char() is expensive complication in this place to begin with. Drop that and adjust the predicate.
Provide timestamptz values to match your column. This also allows indexes to be used (if applicable).
Return Table Type from A function in PostgreSQL
Use time zone names (not offsets or abbreviations) to avoid more misunderstandings.
Ignoring timezones altogether in Rails and PostgreSQL
Use dollar-quoting to clean up the quote mess.
Insert text with single quotes in PostgreSQL
I suggest this as 2nd parameter:
$$
SELECT l.locationcode
FROM locationinfo l
JOIN invoiceinfo b ON b.location = l.locationid
WHERE b.status <> 2 AND l.locationtype = 1 AND l.status = 1
AND b.invoicedate >= timestamptz '2018-03-01 Europe/Vienna'
AND b.invoicedate < timestamptz '2018-03-04 Europe/Vienna'
GROUP BY 1
ORDER BY 1
$$
Replace Europe/Vienna in my example with the time zone name defining your dates.
Note 2018-03-04 to include all of 2018-03-03 like you intended.

add multi tables in from() zend_db_select

i have to do a select from multi tables using zend_db_select for this sql :
SELECT t1.id,t2.ids, t3.uid
FROM table1 t1,table2 t2, table3 t3
this is the code used :
$subQuery = $this->getDbTable ()->select ()->setIntegrityCheck ( false )
->from(array('t1'=>'table1','t2'=>'table2','t3'=>'table3'),array('t1.id','t2.ids','t3.uid'))
->query()
->fetchAll();
so i have message error say that t2.ids is not in the column list
because zend_db_select take just the first table
any solution to resolve this problème ?
thaks
You can use a cross join with:
$subQuery = $this->getDbTable ()->select ()->setIntegrityCheck ( false )
->from(array('t1'=>'table1'),array('t1.id'))
->joinCross(array('t2'=>'table2'),array('t2.ids'))
->joinCross(array('t3'=>'table3'),array('t3.uid'))
->query()
->fetchAll();