CREATE OR REPLACE FUNCTION update()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
with name_array as (select jsonb_array_elements(inputs #> '{lists}') AS lists
from random.model
)
select name_array.lists #>> '{name}' as name,
name_array.lists #>> '{value}' as value
from name_array;
IF NEW.value <> OLD.value THEN
INSERT INTO random.model_tracker(userid,modelid,datetime,oldjsoninput,newjsoninput,action)
Values (old.user_id,old.id,now(),
'{"lists": [{"name": "OLD.name"}, {"value": "OLD.value"}]}'
,'{"lists": [{"name": "NEW.name"},{"value": "NEW.value"}]}'
,'UPDATE');
END IF;
RETURN NEW;
END;
$$
Trigger
CREATE TRIGGER update
AFTER UPDATE
ON random.model
FOR EACH ROW
EXECUTE PROCEDURE update();
When i am running inner query, it produces outputs as text for name and value. This function gets created however when i update values on the table i am getting this error:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function update() line 6 at SQL statement
SQL state: 42601
any select inside of a function need to be placed inside of a variable, that was the error message.
made another version of the json :
CREATE OR REPLACE FUNCTION update()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
IF NEW.value <> OLD.value THEN
INSERT INTO random.model_tracker(userid,modelid,datetime,oldjsoninput,newjsoninput,action)
Values (old.user_id,old.id,now(),
(SELECT * FROM (WITH lists (lists ) AS (
WITH q ( name , value ) AS
( SELECT OLD.name , OLD.value ) SELECT array_to_json( ARRAY[row_to_json(q)] ) FROM q
)SELECT row_to_json(list.*) FROM lists
)) ,
(SELECT * FROM (
WITH lists (lists ) AS (
WITH q ( name , value ) AS
( SELECT NEW.name , NEW.value ) SELECT array_to_json( ARRAY[row_to_json(q)] ) FROM q
)SELECT row_to_json(list.*) FROM lists
)) ,'UPDATE');
END IF;
RETURN NEW;
END;
$$
How to write a constraint (table level unique, using GIST and or EXCLUDE ) to perform duplication record validation using the following rule:
Entered from_date and to_date values should not be equal or within the range, and
Employee_id should not be equal, and
After the validation, an error message should be return saying 'Duplicate Entry'.
This is in postgreSQL.
Note: I am new to postgreSQL (worked in MS SQL Server and MySQL).
Thanks in advance.
As stated by #Laurenz Albe, it sounds like impossible to do with a constraint. You can implement either a trigger function or a rule instead :
Trigger function :
CREATE OR REPLACE FUNCTION test_insert_table()
RETURNS trigger LANGUAGE plpgsql IMMUTABLE AS
$$
BEGIN
IF NEW.status = 'pending'
AND EXISTS
( SELECT 1
FROM your_table
WHERE Employee_id = NEW.Employee_id
AND range #> daterange(NEW.from_date, NEW.to_date)
)
THEN
RAISE EXCEPTION 'Duplicate Entry' ;
RETURN NULL ;
ELSE
RETURN NEW ;
END IF ;
END ;
$$
CREATE OR REPLACE TRIGGER test_insert_table
BEFORE INSERT ON your_table
FOR EACH ROW EXECUTE FUNCTION test_insert_table() ;
Rule :
CREATE OR REPLACE RULE test_insert AS
ON INSERT TO your_table
WHERE NEW.status = 'pending'
AND EXISTS
( SELECT 1
FROM your_table
WHERE Employee_id = NEW.Employee_id
AND range #> daterange(NEW.from_date, NEW.to_date)
)
DO INSTEAD NOTHING ;
I'm writing postgresql function which inserts data and returns successfully inserted data rows.
The code is below.
CREATE OR REPLACE FUNCTION public.fn_insert_test(json_data jsonb)
returns table(col_1 varchar(255),
col_2 varchar(255),
col_3 timestamp)
LANGUAGE plpgsql
AS $function$
declare
--
begin
with my_table as (
with my_table1(my_json) as (
values(
json_data
)
)
insert into "test"(col_1, col_2, col_3)
select
elem->>'val1', elem->>'val2', now()
from
my_table1 t, jsonb_array_elements(my_json->'_data') elem
on conflict(col_1) do nothing
returning *
)
select * from my_table;
end
$function$
;
select fn_insert_test('{"_data": [{"val1":"1", "val2":"1"}, {"val1":"2", "val2":"2"}]}');
It occurs error below.
SQL Error [42702]: ERROR: column reference "col_1" is ambiguous
Detail: It could refer to either a PL/pgSQL variable or a table column.
Where: PL/pgSQL function fn_insert_test(jsonb) line 5 at SQL statement
[edit]
This is not the real problem here. There is a lot of problems in your code :
-> If you want to return a table, you have to use 'return query' : http://www.postgresqltutorial.com/plpgsql-function-returns-a-table/
-> I do not think you can use the WITH like you do: https://www.postgresql.org/docs/current/queries-with.html
Here is a functoinnal version of your code. But I am not quite sure of what you want :
CREATE OR REPLACE FUNCTION public.fn_insert_test(json_data jsonb)
returns table(col_1 varchar(255),
col_2 varchar(255),
col_3 timestamp)
LANGUAGE plpgsql AS
$$
declare
--json_data jsonb := '{"_data": [{"val1":"1", "val2":"1"}, {"val1":"2", "val2":"2"}]}';
begin
create temp table res (col_1 varchar (255), col_2 varchar (255), col_3 timestamp) on commit drop;
with my_table1(my_json) as
(
values(
json_data
)
)
, inserted as
(
insert into test(col_1, col_2, col_3)
select
elem->>'val1', elem->>'val2', now()
from
my_table1 t
, jsonb_array_elements(json_data->'_data') elem
on conflict do nothing
returning *
)
insert into res
select *
from inserted;
--raise notice '%', res_v;
return query select * from res;
end
$$
;
select fn_insert_test('{"_data": [{"val1":"1", "val2":"1"}, {"val1":"2", "val2":"2"}]}');
I am new to Postgres, in ms sql server we can write stored procedure to perform logic and return a select statement. Likewise i wrote following pqsql function with return type table. But its showing some incorrect syntax error, but if I replace the return type with integer and comment out the select statement it works fine.
following is the function with return type table
CREATE OR REPLACE FUNCTION candidate_save
(
p_name varchar(50),
p_dob date,
p_course_level_code integer,
p_email varchar(50),
p_mob character(10),
p_sslc_regno varchar(10),
p_sslc_year_of_passing character(4),
p_sslc_board_of_examination integer,
p_password character(128),
p_ip_address varchar(15)
)
RETURNS TABLE
(
regno char(10),
name varchar(50),
dob date,
course_level_code integer,
email varchar(50),
mob character(10),
sslc_regno varchar(10),
sslc_year_of_passing character(4),
sslc_boe integer
)
AS
$BODY$
DECLARE
max_row_count integer;
random_no integer;
v_regno character(10);
BEGIN
SELECT COUNT(*) INTO max_row_count FROM candidates WHERE course_level_code = p_course_level_code;
max_row_count := max_row_count + 1;
v_regno := cast(p_course_level_code as character) || cast( trunc(random() * 89999 + 10000) as integer) || to_char(max_row_count, 'FM0000');
INSERT INTO candidates
(regno, name, dob, course_level_code, email, mob, sslc_regno, sslc_year_of_passing, sslc_board_of_examination, password, created_on, ip_address)
VALUES
(v_regno, p_name, p_dob, p_course_level_code, p_email, p_mob, p_sslc_regno, p_sslc_year_of_passing, p_sslc_board_of_examination, p_password, now(), p_ip_address);
RETURN QUERY
SELECT regno, name, dob, course_level_name, email, mob, sslc_regno, sslc_year_of_passing, c.board as sslc_boe
FROM candidates a
INNER JOIN course_levels b on a.course_level_code = b.course_level_code
INNER JOIN sslc_board_of_examinations c ON a.sslc_board_of_examination = boe_code
WHERE regno = v_regno;
END;
$BODY$
LANGUAGE plpgsql;
when creating above function following error is showing
ERROR: syntax error at or near "$1"
LINE 1: INSERT INTO candidates ( $1 , $2 , $3 , $4 , $5 , $6 , ...
^
QUERY: INSERT INTO candidates ( $1 , $2 , $3 , $4 , $5 , $6 , $7 , $8 , sslc_board_of_examination, password, created_on, ip_address) VALUES ( $9 , $10 , $11 , $12 , $13 , $14 , $15 , $16 , $17 , $18 , now(), $19 )
CONTEXT: SQL statement in PL/PgSQL function "candidate_save" near line 30
********** Error **********
ERROR: syntax error at or near "$1"
SQL state: 42601
Context: SQL statement in PL/PgSQL function "candidate_save" near line 30
but if I replace the table with integer it works fine.
CREATE OR REPLACE FUNCTION candidate_save
(
p_name varchar(50),
p_dob date,
p_course_level_code integer,
p_email varchar(50),
p_mob character(10),
p_sslc_regno varchar(10),
p_sslc_year_of_passing character(4),
p_sslc_board_of_examination integer,
p_password character(128),
p_ip_address varchar(15)
)
RETURNS integer
AS
$BODY$
DECLARE
max_row_count integer;
random_no integer;
v_regno character(10);
BEGIN
SELECT COUNT(*) INTO max_row_count FROM candidates WHERE course_level_code = p_course_level_code;
max_row_count := max_row_count + 1;
v_regno := cast(p_course_level_code as character) || cast( trunc(random() * 89999 + 10000) as integer) || to_char(max_row_count, 'FM0000');
INSERT INTO candidates
(regno, name, dob, course_level_code, email, mob, sslc_regno, sslc_year_of_passing, sslc_board_of_examination, password, created_on, ip_address)
VALUES
(v_regno, p_name, p_dob, p_course_level_code, p_email, p_mob, p_sslc_regno, p_sslc_year_of_passing, p_sslc_board_of_examination, p_password, now(), p_ip_address);
RETURN 1;
END;
$BODY$
LANGUAGE plpgsql;
if I am doing something wrong pl. let me know.
I am using Postgres 9.4
INSERT INTO candidates
(regno
^------- The error
ERROR: syntax error at or near "$1"
LINE 1: INSERT INTO candidates ( $1
The issue is that regno is a plpgsql variable, because it's a column name in the output table.
RETURNS TABLE
(
regno char(10),
Each entry in RETURNS TABLE is registered as a variable so you can assign to it and use RETURN NEXT.
When parsed and processed, plpgsql variables in statements are replaced with positional parameters like $1, $2, etc. Which is why the error is what it is, and also why some of the later entries in the insert column-name-list don't get replaced. They don't clash with a parameter name.
Use different variable names.
I think 9.5 detects parameter name clashes and reports a clearer error.
finally it started working after I changed the variable names in the return table.
Thanks to all
I am not good at T-SQL. How can does following trigger into T-SQL? For each doesn't work in T-SQL.
CREATE OR REPLACE TRIGGER DSS.TRG_DEPO_STOK_IZLEME
BEFORE INSERT OR UPDATE
ON DSS.CR_DEPO_STOK FOR EACH ROW
BEGIN
INSERT INTO CR_DEPO_STOK_IZLEME
(ID_DEPO_STOK_IZLEME
, ID_DEPO_STOK
, MT_MIKTAR_ESKI
, MT_MIKTAR_YENI
, EKLEME_TARIHI
)
VALUES (SEQ_ID_DEPO_STOK_IZLEME.NEXTVAL
, :NEW.ID_DEPO_STOK
, :OLD.MT_MIKTAR
, :NEW.MT_MIKTAR
, SYSDATE
);
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
Probably something like
CREATE TRIGGER DSS.TRG_DEPO_STOK_IZLEME
ON DSS.CR_DEPO_STOK
AFTER INSERT, UPDATE
AS
BEGIN
INSERT INTO CR_DEPO_STOK_IZLEME
(ID_DEPO_STOK
, MT_MIKTAR_ESKI
, MT_MIKTAR_YENI
, EKLEME_TARIHI
)
SELECT i.ID_DEPO_STOK
, d.MT_MIKTAR
, i.MT_MIKTAR
, GETDATE()
FROM INSERTED i FULL OUTER JOIN DELETED d ON i.pk = d.pk
END;
There are no row triggers in TSQL also sequences will not appear until the next version so I have assumed that ID_DEPO_STOK_IZLEME will be an identity column.