trigger only fired one when i use insert into select - tsql

CREATE TRIGGER tg_bpb_cons_no ON dbo.t_bpb_cons
FOR INSERT
AS
/*
fungsi : membuat document bon permintaan barang maintenance number secara otomatis`
author : ryan
*/
declare #new_doc_no varchar(20)
declare #doc_no varchar(20)
--declare #doc_no bigint
--update doc no
SELECT #doc_no = max(cast(substring(doc_no,9,13) as integer)) from t_bpb_cons
IF (#doc_no IS NULL)
BEGIN
set #doc_no = 0
END
PRINT #DOC_NO
SELECT #new_doc_no = cast(#doc_no+1 as varchar(20))
SELECT #new_doc_no = LEFT('BPB/CON/',8+len(#new_doc_no))+#new_doc_no
UPDATE t_bpb_cons SET doc_no=#new_doc_no WHERE [ID]=(SELECT MAX([ID]) AS id from t_bpb_cons)
it works fine with single record inserted, but i used Insert into tbl select tblvalue from AnotherTable to insert multiple record it's only affected on the last record...
why ??

Insert statement (even having multiple rows) treated as a single operation, you have to handle by yourself the inserted values in the trigger code.
try this :
CREATE TRIGGER tg_bpb_cons_no ON dbo.t_bpb_cons
FOR INSERT
AS
/*
fungsi : membuat document bon permintaan barang maintenance number secara otomatis`
author : ryan
*/
declare #new_doc_no varchar(20)
declare #doc_no int
declare #row_inserted int
select #row_inserted = count(*) from inserted
--declare #doc_no bigint
--update doc no
SELECT #doc_no = max(cast(substring(doc_no,9,13) as integer)) from t_bpb_cons
IF (#doc_no IS NULL)
BEGIN
set #doc_no = 0
END
WHILE #doc_no < #doc_no + #row_inserted
BEGIN
PRINT #DOC_NO
SELECT #new_doc_no = cast(#doc_no+1 as varchar(20))
SELECT #new_doc_no = LEFT('BPB/CON/',8+len(#new_doc_no))+#new_doc_no
UPDATE t_bpb_cons SET doc_no=#new_doc_no WHERE [ID] = (SELECT MAX([ID]) AS id from inserted)
SET #doc_no = #doc_no + 1
END

Related

How insert count of a table in another table attribute by trigger postgresql

I have created two tables "post" and "node" and I want to assign the sum of the entities of the "node" table in the attribute "nb_noeud" of the "post" table by trigger. But, the code below does not work and I think I missed something.
My code is as follows:
CREATE TABLE noeud
(
id_noeud serial NOT NULL,
code_noeud varchar(10) NULL,
type_noeud t_noeud NULL,
phase t_phase NULL
x_32632 bigint NULL,
y_32632 bigint NULL,
geom_noeud geometry(point) NULL,
obs text NULL
)
;
CREATE TABLE poste
(
id_pt serial NOT NULL,
code_pt varchar(8) NULL,
nom_pt varchar(50) NULL,
nb_noeud smallint NULL,
geom_pt geometry(polygon) NULL,
surf_pt numeric(15,2) NULL,
obs text NULL
)
;
CREATE OR REPLACE FUNCTION recap_noeud() RETURNS TRIGGER
language plpgsql AS
$$
DECLARE
som_noeud smallint;
BEGIN
IF (TG_OP = 'INSERT') THEN
SELECT COUNT(*) INTO som_noeud FROM noeud;
UPDATE poste set NEW.nb_noeud = som_noeud;
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
SELECT COUNT(*) INTO som_noeud FROM noeud;
UPDATE poste set NEW.nb_noeud = som_noeud;
RETURN NEW;
ELSIF (TG_OP = 'UPDATE') THEN
RETURN NULL;
ELSE
RAISE WARNING 'Other action occurred: %, at %', TG_OP, now();
RETURN NULL;
END IF;
END;
$$
;
DROP TRIGGER IF EXISTS trig_recap_noeud ON noeud;
CREATE TRIGGER trig_recap_noeud AFTER INSERT OR UPDATE OR DELETE ON noeud FOR EACH ROW EXECUTE PROCEDURE recap_noeud();
Replace DELETE and INSERT clauses with
IF TG_OP = 'INSERT' OR TG_OP = 'DELETE' THEN
SELECT COUNT(*) INTO som_noeud FROM noeud;
UPDATE poste set nb_noeud = som_noeud;
RETURN NULL;
Best regards, Bjarni

trigger in postgresql old value and new value

how to write trigger in postgresql which maintain old value, new value and table name.
I have 5 tables and each tables is different data structure i want to maintain audit details in single table with old value new value and table name.old value and new value contain multiple columns in json format with column name and value.
example
audit_details
----------------------------------------------------------------
date_time|table_name|old_data|new_data|user|primary_key_of_table
----------------------------------------------------------------
I wrote sample trigger function for you. You can make additional changes yourself.
CREATE TABLE test.log_table_data (
id serial not null,
schema_name varchar(100) NOT NULL,
table_name varchar(100) NOT NULL,
action_date timestamp NOT NULL DEFAULT now(),
action_type varchar(10) NOT NULL,
table_id int4 NOT NULL,
old_data jsonb NULL,
new_data jsonb NULL,
CONSTRAINT log_table_data_pk PRIMARY KEY (id)
);
create or replace function test.register_as_log()
returns trigger
language plpgsql
security definer
as $function$
declare
v_old_data json;
v_new_data json;
shemaname varchar;
tablename varchar;
begin
shemaname = tg_table_schema;
tablename = tg_table_name;
/* json_strip_nulls - removes null values */
if (tg_op = 'UPDATE') then
v_old_data = (select json_strip_nulls(row_to_json(old.*)));
v_new_data = (select json_strip_nulls(row_to_json(new.*)));
insert into test.log_table_data (schema_name, table_name, action_type, table_id, old_data, new_data)
values (shemaname, tablename, 'update', old.id, v_old_data, v_new_data);
return new;
end if;
if (tg_op = 'DELETE') then
v_old_data = (select json_strip_nulls(row_to_json(old.*)));
insert into test.log_table_data (schema_name, table_name, action_type, table_id, old_data, new_data)
values (shemaname, tablename, 'delete', old.id, v_old_data, null);
return old;
end if;
end;
$function$
;

Error Incorrect syntax

I have created a procedure in Sybase
create procedure prcrms_crms_cust_id_verify_ins(#customer_code numeric(12,0),#id_type tinyint,#verification_status varchar(12),#verification_response varchar(255),#verification_date datetime,#add_user varchar(21)) as
begin
declare #check_id_exists int
select #check_id_exists = count(*) from crms_customer_id_verification where ( ('customer_code'=#customer_code) and ('id_type'=#id_type))
if(#check_id_exists > 0)
begin
update crms_customer_id_verification set verification_status=#verification_status,verification_response=#verification_response,verification_date=#verification_date where ( ('customer_code'=#customer_code) and ('id_type'=#id_type))
return ##rowcount
end
if((#check_id_exists <> null) or (#check_id_exists <> 0))
begin
insert into crms_customer_id_verification(customer_code,id_type,verification_status,verification_response,verification_date,add_user) values(#customer_code,#id_type,#verification_status,#verification_response,#verification_date,#add_user)
return ##rowcount
end
end
when i try to execute the procedure
exec prcrms_crms_cust_id_verify_ins(3344,0,"VERIFIED",'{test:test}','1998-09-09 12:12:12.000','Admin')
it shows Incorrect syntax near '3344'.
/*
create procedure prcrms_crms_cust_verify_ins(#customer_code varchar(255),#id_type varchar(255) ,#verification_status varchar(12),#verification_response varchar(255),#verification_date varchar(255),#add_user varchar(21))as
/*
** ------------------------------------
** Created By : Bibil Mathew Chacko
** Created On : Jul 16 2016
** Description : insert in crms_customer_id_verification if id_type and customer exist.Update table if customer and id_type exist.
** -------------------------------------
*/
begin
declare
#check_id_exists int,
#cc numeric,
#id_t tinyint,
#vd datetime
select #cc = convert(numeric(12,0),#customer_code)
select #id_t = convert(tinyint,#id_type)
select #vd = convert(datetime,#verification_date)
select #check_id_exists = count(*) from crms_customer_id_verification where ( (customer_code=#cc) and (id_type=#id_t))
if(#check_id_exists > 0)
begin
update crms_customer_id_verification set verification_status=#verification_status,verification_response=#verification_response,verification_date=#vd where (customer_code=#cc and id_type=#id_t)
return ##rowcount
end
if((#check_id_exists <> null) or (#check_id_exists <> 0))
begin
insert into crms_customer_id_verification(customer_code,id_type,verification_status,verification_response,verification_date,add_user) values(#cc,#id_t,#verification_status,#verification_response,#vd,#add_user)
return ##rowcount
end
end
*/
/*exec prcrms_crms_cust_verify_ins '3344','0',"VERIFIED",'{test:test}','1998-09-09 12:12:12.000','Admin'*/
Should use VARCHAR type as parameter and procedure should have support for converting to required type. Another mistake I have done is Sybase Procedures don't have parenthesis.

How does one use loops in TSQL?

In TSQL, I would like to change the following code from have to use hard coded dhomes to using a loop for optimization. My failed attempt at trying to add a loop is also included.
Declare #dhome Tinyint, #bp smallint, #lr smallint, #q smallint
// Set #dhome = 1
While(#dhome <= 3) // My attempt to add a loop
SELECT #lr = MAX(NQdDate), #q = NQd
FROM NQdHistory
WHERE dhomeId = #dhome
GROUP BY NQdDate, NQd
SELECT #bd = COUNT(*)
FROM bdhome
WHERE NQdDate= #lr AND dhomeID= #dhome
DELETE FROM ND1 WITH(XLOCK)
WHERE dhomeID= #dhome AND NQdDate= #lr
UPDATE NQdHistory
SET Nbd = #q - ##RowCount - #bp, NBd = #bp
WHERE NQdDate= #lr AND dhomeID= #dhome
Set #dhome = #dhome +1 //My attempt to end a loop
You're on the right track. You're missing your begin and end. Also, be sure to give #dhome a value. It looks like you started to and have it commented out on your third line:
Declare #dhome Tinyint, #bp smallint, #lr smallint, #q smallint
// Set #dhome = 1
While(#dhome <= 3) // My attempt to add a loop
begin
SELECT #lr = MAX(NQdDate), #q = NQd
FROM NQdHistory
WHERE dhomeId = #dhome
GROUP BY NQdDate, NQd
SELECT #bd = COUNT(*)
FROM bdhome
WHERE NQdDate= #lr AND dhomeID= #dhome
DELETE FROM ND1 WITH(XLOCK)
WHERE dhomeID= #dhome AND NQdDate= #lr
UPDATE NQdHistory
SET Nbd = #q - ##RowCount - #bp, NBd = #bp
WHERE NQdDate= #lr AND dhomeID= #dhome
Set #dhome = #dhome +1 //My attempt to end a loop
end
If you're familiar with C/C#/C++, think of T-SQL's Begin and End like curly braces { and }, if you're more familiar with VB Then and End If. Or more like pascals Begin and End. You get the idea :)
Missing a begin and end on your while.
WHILE (Transact-SQL)
Example 1
DECLARE #I INT,#COUNTVAR INT
SET #I = 1
DECLARE #Parent_Child TABLE(ID INT IDENTITY(1,1),ParentPositionID INT NULL,ChildPositionId Int)
INSERT INTO #Parent_Child(ParentPositionID,ChildPositionId)
SELECT DISTINCT PARENT_POSITION_ID,CHILD_POSITION_ID from tblPOSITION_HIERARCHY
--WHERE CHILD_POSITION_ID IN (--YOUR CONDITION IF ANY)
SELECT #COUNTVAR =COUNT(*) FROM #PTS_Parent_Child
DECLARE #int_SUPE_POSITION_ID INT, #int_CHILD_POSITION_ID INT
--loop through records here
WHILE #I <= #COUNTVAR
BEGIN
SELECT #int_SUPE_POSITION_ID=ParentPositionID,#int_CHILD_POSITION_ID=ChildPositionId FROM #Parent_Child WHERE ID=#I
--Whatever you want to do with records
SET #I=#I+1
END
Example 2
Just another approach if you are fine using temp tables.I have personally tested this and it will not cause any exception (even if temp table does not have any data.)
CREATE TABLE #TempTable
(
ROWID int identity(1,1) primary key,
HIERARCHY_ID_TO_UPDATE int,
)
--INSERT DATA INTO TEMP TABLE USING INSERT INTO CLAUSE OR FOR EAXMPLE BELOW
--INSERT INTO #TempTable VALUES(1)
--INSERT INTO #TempTable VALUES(2)
--INSERT INTO #TempTable VALUES(4)
--INSERT INTO #TempTable VALUES(6)
--INSERT INTO ##TempTable VALUES(8)
DECLARE #MAXID INT
SET #COUNTER =1
SELECT #MAXID=COUNT(*) FROM #TempTable
--PRINT #MAXID
WHILE (#MAXID > 0)
BEGIN
--DO THE PROCESSING HERE
SELECT #HIERARCHY_ID_TO_UPDATE =PT.HIERARCHY_ID_TO_UPDATE FROM #TempTable PT WHERE ROWID=#COUNTER
--PRINT '#MAXID VALUE '
--PRINT #MAXID
SET #MAXID=#MAXID-1
SET #COUNTER =#COUNTER + 1
End
If(OBJECT_ID('tempdb..#TempTable') IS NOT NULL)
BEGIN
DROP TABLE #TempTable
END

Assign a list of integers to an #var

I can:
declare #idOrder int
set #idOrder = 21319
I want:
declare #idOrder int
set #idOrder = (21319, 21320)
for use in a series of statements where the 'WHERE' clause uses the IN operator
delete Orders
where idOrder in #idOrder
instead of
delete Orders
where idOrder in (21319, 21320)
You can't do that as long as it's an int, as that's not a valid value for that datatype. A datatype that could take several integers is a table
declare #idOrder table (id int)
insert into #idOrder values(21319)
insert into #idOrder values(21320)
delete from Orders where idOrder in (select id from #idOrder)
In SQL Server you can also
CREATE FUNCTION [dbo].[fn_ado_param_int] (#ado nvarchar(4000))
RETURNS #VALUES TABLE (ado int)AS
BEGIN
declare #Delim char(1)
set #Delim = ','
DECLARE #chrind INT
DECLARE #Piece nvarchar(4000)
SELECT #chrind = 1
WHILE #chrind > 0
BEGIN
SELECT #chrind = CHARINDEX(#Delim,#ado)
IF #chrind > 0
SELECT #Piece = LEFT(#ado,#chrind - 1)
ELSE
SELECT #Piece = #ado
INSERT #VALUES(ado) VALUES(#Piece)
SELECT #ado = RIGHT(#ado,LEN(#ado) - #chrind)
IF LEN(#ado) = 0 BREAK
END
RETURN
END
declare #idOrder varchar(500);
set #inOrder = "21319,2138,2138";
delete from Orders where id in (select ado from dbo.fn_ado_param_int(#idOrder));