Postgresql :Syntax issue in MERGE with JSON param in stored function - sql

Facing syntax issue when I have json input, which needs to be insert/update values from JSON into the table which is a view
Expected
When Primary id matched with Item_id (PK) - update its corresponding values
When Primary id not matched with Item_id (PK) - insert into the view
Sample SP
drop function if exists sp_post_itemsx;
CREATE FUNCTION sp_post_itemsx(i_data jsonb)
RETURNS VOID
AS $function$
BEGIN
MERGE INTO vw_item_status_detail
USING
(SELECT
i_data->>'fulfillerId' fulfillerId,
t->>'itemId' itemId,
i_data->>'orderId' orderId,
1000,
t->>'skuCode' skuCode,
t->>'decorationTechnology' decorationTechnology,
(t->>'quantity')::numeric quantity ,
NOW()
FROM jsonb_array_elements(i_data -> 'items')) as t ON item_id = t.itemId
WHEN MATCHED THEN UPDATE SET
vw.quantity = t.quantity
WHEN NOT MATCHED THEN
INSERT INTO vw_item_status_detail(
fulfiller_id,
item_id,
order_id,
status_id,
sku_code,
decoration_technology,
quantity,
item_updated_time)
SELECT
i_data->>'fulfillerId' fulfillerId,
t->>'itemId' itemId,
i_data->>'orderId' orderId,
1000,
t->>'skuCode' skuCode,
t->>'decorationTechnology' decorationTechnology,
(t->>'quantity')::numeric quantity ,
NOW()
FROM jsonb_array_elements(i_data -> 'items') t ;
END;
$function$
LANGUAGE plpgsql;
ERROR: "vw_item_status_detail" is not a known variable
Not sure what is wrong with the syntax or MERGE doesn't work with insert for views table

Related

why does my trigger function cause a null error?

PostgreSQL.
My trigger func:
CREATE OR REPLACE FUNCTION new_purchase() RETURNS TRIGGER AS $psql$
BEGIN
IF NOT EXISTS(
SELECT 1
FROM currents c
WHERE c.name = new.name
)
THEN
INSERT INTO currents (name, qty)
VALUES (new.name, new.qty);
ELSE
UPDATE currents
SET
qty = qty + new.qty
WHERE
name = new.name;
END IF;
return new;
END;
$psql$ language plpgsql;
Then my trigger:
create trigger new_purchase_trigger
after insert on purchases
for each statement
execute procedure new_purchase();
my two tables with which i am manipulating:
Purchases
CREATE TABLE purchases (
name VARCHAR,
date TIMESTAMP,
qty INTEGER,
price NUMERIC,
about VARCHAR
)
Currents
CREATE TABLE currents (
name VARCHAR,
qty INTEGER
)
My INSERT:
INSERT INTO purchases (name, date, qty, price, about)
VALUES ('cheese', '2022-07-31', 1000, 11500, 'holland');
And finally the error when i am adding data to purchases via INSERT INTO - VALUES:
ERROR: NULL value in column "name" of relation "currents" violates the NOT NULL constraint
DETAIL: Error string contains (null, null).
CONTEXT: SQL statement: "INSERT INTO currents (name, qty)
VALUES(new.name, new.qty)"
PL/pgSQL new_purchase() function, line 9, statement SQL statement
SQL state: 23502
You need a ROW level trigger for what you are trying to achieve. In a statement level trigger (for each statement) the record new is not populated:
create trigger new_purchase_trigger
after insert on purchases
for each row
execute procedure new_purchase();
Note that you can simplify your trigger function if you declare currents.name as the primary key:
CREATE OR REPLACE FUNCTION new_purchase()
RETURNS TRIGGER
AS $psql$
BEGIN
INSERT INTO currents (name, qty)
VALUES (new.name, new.qty)
on conflict (name) do update
set qty = currents.qty + excluded.qty;
return new;
END;
$psql$
language plpgsql;

PostgreSQL: Trigger INSERT INTO SELECT from other table

I'm trying to create a trigger that will add a new row processed entry to a destination table each time a new row is created in the source table.
Step 1 Create destination table:
CREATE TABLE public.destination_table (
id serial PRIMARY KEY,
created_at TIMESTAMP NOT NULL,
sale_id INTEGER NOT NULL,
product_id INTEGER NOT NULL,
product_name VARCHAR NOT NULL,
url VARCHAR NOT NULL,
shop_id VARCHAR NOT NULL,
user_id VARCHAR)
Step 2 Create trigger function:
CREATE OR REPLACE FUNCTION triger_function() RETURNS TRIGGER AS
$BODY$
BEGIN
INSERT INTO public.destination_table ( created_at, sale_id, product_id, product_name, url, shop_id, user_id)
SELECT created_at,
sale_id,
product_id,
product_name,
split_part(url::text, '?'::text, 1) AS url,
shop_id,
((((((((data #>> '{}'::text[])::jsonb) #>> '{}'::text[])::jsonb) -> 'local_storage'::text) -> 'data'::text) #>> '{}'::text[])::jsonb) ->> 'user_id'::varchar AS user_id
FROM source_table;
RETURN new;
END;
$BODY$
language plpgsql;
** The Select query inside function work normally when single running.
Step 3 Create trigger:
CREATE TRIGGER trigger_records
AFTER INSERT ON public.source_table
FOR EACH ROW
EXECUTE PROCEDURE triger_function();
The problem is that Trigger does not work, which means it does not record new entries in the target table. Can't figure out where the error is.
You should be using the NEW record in the trigger function to reference the newly inserted data instead of a select, i.e.:
CREATE OR REPLACE FUNCTION triger_function() RETURNS TRIGGER AS
$BODY$
BEGIN
INSERT INTO public.destination_table ( created_at, sale_id, product_id, product_name, url, shop_id, user_id)
VALUES(NEW.created_at,
NEW.sale_id,
NEW.product_id,
NEW.product_name,
split_part(NEW.url::text, '?'::text, 1),
NEW.shop_id,
((((((((NEW.data #>> '{}'::text[])::jsonb) #>> '{}'::text[])::jsonb) -> 'local_storage'::text) -> 'data'::text) #>> '{}'::text[])::jsonb) ->> 'user_id'::varchar)
RETURN new;
END;
$BODY$
language plpgsql;

Postgresql : Best way to handle upsert with Jsonb data in Postgresql

Trying to handle Put/Patch request in the below SP along with insert if new primary values are recieved if I get unique Key constraint which is item_id in our case
Primary Key : ItemId
If no unique key constraint insert into view
If unique key constraint occurs i.e. json which has same itemId upsert its properties viz. quantity,status,etc.
Stored procedure
CREATE OR REPLACE FUNCTION sp_post_items1(i_data jsonb)
RETURNS TABLE(
fulfiller_id varchar,
item_id varchar,
order_id varchar,
status_id integer,
item_updated_time timestamp without time zone)
AS $function$
DECLARE
itemId1 varchar := null;
statusId1 integer := 1000;
quantity1 numeric;
begin
--SELECT t->>'itemId' itemId ,t->>'statusId' statusId,(t->>'quantity')::numeric quantity INTO itemId1,statusId1,quantity1 FROM jsonb_array_elements(i_data -> 'items') t ;
INSERT INTO vw_item_status_detail(
fulfiller_id,
item_id,
order_id,
status_id,
sku_code,
decoration_technology,
quantity,
item_updated_time)
SELECT
i_data->>'fulfillerId' fulfillerId,
t->>'itemId' itemId,
i_data->>'orderId' orderId,
1000,
t->>'skuCode' skuCode,
t->>'decorationTechnology' decorationTechnology,
(t->>'quantity')::numeric quantity ,
NOW()
FROM jsonb_array_elements(i_data -> 'items') t ;
exception when unique_violation then
update vw_item_status_detail v1 set quantity = coalesce (quantity1 , V1.quantity ), status_id = coalesce (statusId1, V1.status_id ), item_updated_time = now() where v1.item_id = itemId1 ;
RETURN QUERY SELECT
v.fulfiller_id fulfiller_id,
v.item_id item_id,
v.order_id order_id,
v.status_id status_id,
v.item_updated_time item_updated_time
FROM vw_item_status_detail v
WHERE (v.order_id = (SELECT i_data->>'orderId') )
AND (v.fulfiller_id = (SELECT i_data->>'fulfillerId'));
END;
$function$
LANGUAGE plpgsql;
Sample sp call along with JSON
select * from sp_post_items1('{"orderId": "newtestput1",
"fulfillerId":"kv0fdt6cx7",
"orderDetailsUrl":"het",
"items":[
{
"attributes":
[{"name":"OracleSku","value":"DWj"},{"name":"taskId","value":"33a1595-e36769876c52"},{"name":"height","value":"5.5"},
{"name":"width","value":"32.004"},{"name":"productFamily","value":"DWT"},{"name":"template","value":"GI-AST70W"},
{"name":"labelInfo","value":"DWU-ROHS,LMQ-DBLU-BLU"},{"name":"decorationTechnology","value":"laserEngraving"},
{"name":"material","value":"Rubber LMQ + LHY"},{"name":"XYZ_barcode","value":"21234348.1"},{"name":"orderType","value":"text"},
{"name":"scheduledShipDate","value":"2020-09-12T23:59:00"},{"name":"orderReference","value":"21235677.9"},{"name":"docRefUrl","value":""},{"name":"additionalInfo","value":""}],
"decorationTechnology":"laserEngraving","itemDescription":"Test Sku for Oracle testing",
"itemId":"item1",
"manufacturingUrl":"htighess",
"skuCode":"CIM-QYXB3789","productName":"Test Sku for Oracle testing","quantity":"2000","taskId":"33a1ea44-1f45-4f2d-9595-e36769876c52"
},
{
"attributes":
[{"name":"OracleSku","value":"DWT-XXX-B3LUX-BB-C"},{"name":"taskId","value":"33a1ea44-1f45-4f6c52"},{"name":"height","value":"5.5"},
{"name":"width","value":"32.004"},{"name":"productFamily","value":"DWT"},{"name":"template","value":"GIFTSET-DWT-INDX-AST70W"},
{"name":"labelInfo","value":"DWK-DBLU-BLU"},{"name":"decorationTechnology","value":"laserEngraving"},
{"name":"material","value":"Rubber LMQ + LHY"},{"name":"XYZ_barcode","value":"21234348.1"},{"name":"orderType","value":"text"},
{"name":"scheduledShipDate","value":"2020-09-12T23:59:00"},{"name":"orderReference","value":"21235677.9"},{"name":"docRefUrl","value":""},{"name":"additionalInfo","value":""}],
"decorationTechnology":"laserEngraving","itemDescription":"Test Sku for Oracle testing",
"itemId":"item2",
"manufacturingUrl":"httpdfg",
"skuCode":"CIM-QYXB3789","productName":"Test Sku for Oracle testing","quantity":"1000","taskId":"33a1edfge36769876c52"
}
]
}'::jsonb)
tried of using a for loop but its not the most optimized way to handle such scenario
Tried approach: 1.To create a temp table , but was not successful
We can user from / not in clause combination clause to insert as well as update in this case

Set insert trigger - value to highest value in column + 1

I have a lists table with the following columns
lists:
- id
- category_id
- name
- sort_order
When adding a new row to the table I want to set the value of the sort order to the highest sort order value + 1 where the category_id is the same as the new row's category_id. Is there a way to achieve this?
UPDATE
So with the recommnendation to create an insert trigger I tried this
CREATE FUNCTION set_list_sort_order()
RETURNS trigger AS $$
BEGIN
NEW.sort_order := select (select sort_order from lists where category_id = NEW.category_id order by sort_order DESC limit 1) + 1
RETURN NEW;
END
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER set_list_sort_order_trigger
BEFORE INSERT ON lists
FOR EACH ROW
EXECUTE PROCEDURE set_list_sort_order()
But I get this error:
ERROR: syntax error at or near "select"
LINE 4: NEW.sort_order := select (select sort_order from lists w...
You can set up a trigger. Or you can set up the logic directly in the insert:
insert into lists (category_id, name, sort_order)
select category_id, name,
coalesce(max(sort_order) + 1, 1)
from (values (?, ?)) v(category_id, name) left join
lists l
using (category_id)
group by v.category_id, v.name;
Note that a query like this could have race conditions. So, you might want to go the route of using a trigger.
you can try to create stored procedure with something like this:
DEClARE #category_id INT = 1
;WITH NextNum AS
(
SELECT
CASE
WHEN MAX(Table1.sort_order) IS NULL THEN 1
ELSE MAX(Table1.sort_order) + 1
END AS NextValue
FROM Table1 AS Table1
WHERE Table1.category_id = #category_id
)
INSERT INTO Table1
(
id
category_id
name
sort_order
)
SELECT #id,
#category_id
#name
NextNum.NextValue
FROM NextNum

Get ID of last inserted row and use it to insert into another table in a stored procedure

I have the following stored procedure which we use to insert data into a table:
CREATE OR REPLACE PROCEDURE mySproc
(
invoiceId IN NUMBER
customerId IN NUMBER
)
IS
BEGIN
INSERT INTO myTable (INVOICE_ID)
VALUES (invoiceId);
END mySproc;
/
What I am trying to do is to get the last inserted ID (this is the primary key field on myTable and auto incremented using a sequence) and insert it into another table, I have tried the following but could not get it working:
CREATE OR REPLACE PROCEDURE mySproc
(
invoiceId IN NUMBER
customerId IN NUMBER
)
IS
BEGIN
INSERT INTO myTable (INVOICE_ID)
VALUES (invoiceId)
returning id into v_id;
INSERT INTO anotherTable (ID, customerID)
VALUES (v_id, customerId);
END mySproc;
/
I am getting this error: [Error] PLS-00049 (59: 26): PLS-00049: bad bind variable 'V_ID' I think I need to declare v_id somewhere but I tried before and after the BEGIN statement but that gave another error.
Any ideas as to how to do this?
Thanks
Change your procedure to
CREATE OR REPLACE PROCEDURE mySproc
(
invoiceId IN NUMBER, -- Added comma
customerId IN NUMBER
)
IS
v_id NUMBER; -- ADDED
BEGIN
INSERT INTO myTable (INVOICE_ID)
VALUES (invoiceId)
returning id into v_id;
INSERT INTO anotherTable (ID, customerID)
VALUES (v_id, customerId);
END mySproc;
Share and enjoy.