Update on multiple jsonb rows with one query in PostgreSQL - postgresql

I have a couple of update queries that I want to be able to run in the same query. (PostgreSQL)
What is the best way to be able to turn this 4 update statements into just 1? Separately they work fine.
with d2 as(
select d.*,arr.elem, arr.pos_elem,elem->>'expression' as expr,elem->>'value' as val ,('{'||pos_elem-1||',default}')::text[] as path
from data_r d,
jsonb_array_elements(d.js) with ordinality arr(elem,pos_elem)
where elem->>'expression' in ('p_start','p_end') or elem->>'value' in (':period_start',':period_end)
)
update queries q
set reports_function_parameters = jsonb_set(reports_function_parameters::jsonb,d2.path,'"Date.new((Date.today.month<2 ? Date.today.year - 2 : Date.today.last_year.year),7,1)"',false)
from d2 where d2.expr = 'p_start'
and q.name in ('HK1','HK2')
update queries q
set reports_function_parameters = jsonb_set(reports_function_parameters::jsonb,d2.path,'"Date.new((Date.today.month<2 ? Date.today.last_year.year : Date.today.year),6,30)"',false)
from d2 where d2.expr = 'p_end'
and q.name in ('HK1','HK2')
update queries q
set reports_function_parameters = jsonb_set(reports_function_parameters::jsonb,d2.path,'"Date.new((Date.today.month<2 ? Date.today.last_year.year : Date.today.year), 1, 1)"',false)
from d2 where d2.val = ':period_start'
and q.name = 'Bookings'
update queries q
set reports_function_parameters = jsonb_set(reports_function_parameters::jsonb,d2.path,'"Date.new((Date.today.month<2 ? Date.today.last_year.year : Date.today.year), 12, 31)"',false)
from d2 where d2.val = ':period_end'
and q.name = 'Bookings'
I've tried to rewrite my update query after reading this thread Update multiple rows in same query using PostgreSQL but I don't get it to work and I don't know if this solution will work for my case.

Related

Update PgSQL Self JOIN With Custom Values

I'm trying to use UPDATE SELF JOIN and could not seem to get the correct SQL query.
Before the query, I execute this SQL query to get the values:
SELECT DISTINCT ON (purpose) purpose FROM user_assigned_customer
sales_manager
main_contact
representative
administrator
By the time I run this query, it overwrites all the purpose columns:
UPDATE user_assigned_customer SET purpose = (
SELECT 'main_supervisor' AS purpose FROM user_assigned_customer AS assigned_user
LEFT JOIN app_user ON app_user.id = assigned_user.app_user_id
WHERE app_user.role = 'supervisor'
AND user_assigned_customer.purpose IS NULL
AND assigned_user.id = user_assigned_customer.id
)
The purpose column is now only showing when running the first query:
main_supervisor
Wondering if there is a way to query to update SQL Self JOIN with a custom value.
I think I got it with a help of a friend.
UPDATE user_assigned_customer SET purpose = 'main_supervisor'
FROM user_assigned_customer AS assigned_user
LEFT JOIN app_user ON app_user.id = assigned_user.app_user_id
WHERE app_user.role = 'supervisor'
AND user_assigned_customer.purpose IS NULL
AND assigned_user.id = user_assigned_customer.id

oracle merge query in postgres

I have this merge query in oracle and it was working fine. Now we are migrating to postgres 10 and trying to find equivalent for this in postgres.
MERGE INTO s.act_pack C USING((SELECT A.jid, A.pid, B.pcode,
B.mc, A.md, A.hd FROM s.act_pack A INNER JOIN s.act_pack B
ON A.pid = B.pid AND A.pcode = B.mc AND (A.hd <> B.hd
OR A.md<> B.md)) order by A.upd_ts desc) D ON(C.pid = D.pid AND
C.pcode = D.pcode AND C.jid = D.jid) WHEN MATCHED THEN UPDATE SET C.md =
D.md, C.hd= D.hd;
I see some forums on web says postgres doesnt support merge, and use INSERT ... ON CONFLICT
but with no background in postgres, I am not able to understand how this complex query can be written using that.
And some says postgres9.5 and above support merge statement. since we are using postgres 10 tried to use same oracle query in postgres but recieved ERROR: syntax error at or near "MERGE"
Any help is highly appreciated.
You don't need an "UPSERT" as you are not doing an INSERT, so a regular UPDATE is enough:
update act_pack C
SET C.md = D.md,
C.hd = D.h
from (
SELECT A.jid, A.pid, B.pcode, B.mc, A.md, A.hd
FROM s.act_pack A
INNER JOIN s.act_pack B
ON A.pid = B.pid
AND A.pcode = B.mc
AND (A.hd <> B.hd OR A.md<> B.md)
) d
where C.pid = D.pid
AND C.pcode = D.pcode
AND C.jid = D.jid
This is a direct "translation" of your code. But the fact that the same table is used three times is a bit strange. But without more information it's hard to know where exactly this could be made more efficient.

Optimizing Postgres query with timestamp filter

I have a query:
SELECT DISTINCT ON (analytics_staging_v2s.event_type, sent_email_v2s.recipient, sent_email_v2s.sent) sent_email_v2s.id, sent_email_v2s.user_id, analytics_staging_v2s.event_type, sent_email_v2s.campaign_id, sent_email_v2s.recipient, sent_email_v2s.sent, sent_email_v2s.stage, sent_email_v2s.sequence_id, people.role, people.company, people.first_name, people.last_name, sequences.name as sequence_name
FROM "sent_email_v2s"
LEFT JOIN analytics_staging_v2s ON sent_email_v2s.id = analytics_staging_v2s.sent_email_v2_id
JOIN people ON sent_email_v2s.person_id = people.id
JOIN sequences on sent_email_v2s.sequence_id = sequences.id
JOIN users ON sent_email_v2s.user_id = users.id
WHERE "sent_email_v2s"."status" = 1
AND "people"."person_type" = 0
AND (sent_email_v2s.sequence_id = 1888) AND (sent_email_v2s.sent >= '2016-03-18')
AND "users"."team_id" = 1
When I run EXPLAIN ANALYZE on it, I get:
Then, if I change that to the following (Just removing the (sent_email_v2s.sent >= '2016-03-18')) as follows:
SELECT DISTINCT ON (analytics_staging_v2s.event_type, sent_email_v2s.recipient, sent_email_v2s.sent) sent_email_v2s.id, sent_email_v2s.user_id, analytics_staging_v2s.event_type, sent_email_v2s.campaign_id, sent_email_v2s.recipient, sent_email_v2s.sent, sent_email_v2s.stage, sent_email_v2s.sequence_id, people.role, people.company, people.first_name, people.last_name, sequences.name as sequence_name
FROM "sent_email_v2s"
LEFT JOIN analytics_staging_v2s ON sent_email_v2s.id = analytics_staging_v2s.sent_email_v2_id
JOIN people ON sent_email_v2s.person_id = people.id
JOIN sequences on sent_email_v2s.sequence_id = sequences.id
JOIN users ON sent_email_v2s.user_id = users.id
WHERE "sent_email_v2s"."status" = 1
AND "people"."person_type" = 0
AND (sent_email_v2s.sequence_id = 1888) AND "users"."team_id" = 1
when I run EXPLAIN ANALYZE on this query, the results are:
EDIT:
The results above from today are about as I expected. When I ran this last night, however, the difference created by including the timestamp filter was about 100x slower (0.5s -> 59s). The EXPLAIN ANALYZE from last night showed all of the time increase to be attributed to the first unique/sort operation in the query plan above.
Could there be some kind of caching issue here? I am worried now that there might be something else going on (transiently) that might make this query take 100x longer since it happened at least once.
Any thoughts are appreciated!

Updating using subqueries sql server 2008

There are two update queries and 1st update query execute successfully but 2nd update query is not execute and show the following message:
Msg 512, Level 16, State 1, Line 10
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. The statement has been terminated.
1st update query:
update dbo.TblPrePostApproval
set
dbo.TblPrePostApproval.PAApprovedDate = (select dbo.TblMasterInfo.AppRefDate
from dbo.TblMasterInfo
Where dbo.TblMasterInfo.Appid = dbo.TblPrePostApproval.Appid),
dbo.TblPrePostApproval.PAApprovedTenor = '36',
dbo.TblPrePostApproval.PAApprovedAmt = (select dbo.TblMasterInfo.AppReqeustAmt
from dbo.TblMasterInfo
where dbo.TblPrePostApproval.Appid = dbo.TblMasterInfo.AppID),
dbo.TblPrePostApproval.PADisbBr = (select dbo.TblMasterInfo.AppSourceBrName
from dbo.TblMasterInfo
where dbo.TblPrePostApproval.Appid = dbo.TblMasterInfo.AppID)
2nd update query
update dbo.TblPrePostApproval
set
dbo.TblPrePostApproval.PAApprovedDate = (select dbo.TestPost.PADate
from dbo.TestPost
Where dbo.TestPost.Appid = dbo.TblPrePostApproval.Appid),
dbo.TblPrePostApproval.PAApprovedTenor = (select dbo.TestPost.PATenor
from dbo.TestPost
Where dbo.TestPost.Appid = dbo.TblPrePostApproval.Appid),
dbo.TblPrePostApproval.PAApprovedAmt = (select dbo.TestPost.PAAmt
from dbo.TestPost
where dbo.TestPost.Appid = dbo.TblPrePostApproval.AppID),
dbo.TblPrePostApproval.PADisbBr = (select dbo.TestPost.PABr
from dbo.TestPost
where dbo.TestPost.Appid = dbo.TblPrePostApproval.AppID)
Where is my problem? Pls any one suggest me.
One of your subqueries (I guess on line 10) is returning more than one row, so it can't check to see if it equals anything, because it's a set, not a value. Just change your query to be more specific. Try adding LIMIT 0, 1 to the end of the subqueries, or TOP (1) after the the SELECT in each subquery.
Why don't you use JOINs for your update? Much easier to read and understand!
Query #1:
UPDATE ppa
SET
PAApprovedDate = info.AppRefDate,
PAApprovedTenor = '36',
PAApprovedAmt = info.AppReqeustAmt,
PADisbBr = info.AppSourceBrName
FROM
dbo.TblPrePostApproval ppa
INNER JOIN
dbo.TblMasterInfo.TblMasterInfo info ON info.Appid = ppa.Appid
Query #2:
UPDATE ppa
SET
PAApprovedDate = tp.PADate,
PAApprovedTenor = tp.PATenor,
PAApprovedAmt = tp.PAAmt,
PADisbBr = tp.PABr
FROM
dbo.TblPrePostApproval ppa
INNER JOIN
dbo.TestPost tp ON tp.Appid = ppa.AppID

Oracle query not executing in PostgreSQL

I have a query :
update (select tmp."table1" as tmpid,
del."table1" as delid
from "table1_TMP" tmp ,
"table1_DEL" del
where del."table2" = tmp."table2" and
del."REFSEQNO" = tmp."REFSEQNO")
set tmpid = delid;
This query runs in oracle without any problem.
How can I modify this query to run on Postgresql?
I think this would do it.
update "table1_TMP" tmp
set "table1" = del."table1"
from "table1_DEL" del
where del."table2" = tmp."table2" and
del."REFSEQNO" = tmp."REFSEQNO"