TSQL trigger instead of insert - sql-server

I need to replace, after an insert in a certain table, one of the column value if it match with a banned value.
example:
INSERT INTO [dbo].[TEST_A]
([COL_A]
,[COL_B])
VALUES
('TEST'
,'TEST1')
TEST1 is a banned value and I want to replace it in 'BANNED'.
This is the trigger I wrote but it seems to working properly well:
CREATE TRIGGER [dbo].[TEST_NAME_INS] ON [dbo].[TEST_A]
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO TEST_A
(COL_A
,COL_B)
SELECT
COL_A
,REPLACE(COL_B, 'TEST1', 'BANNED')
FROM inserted
WHERE INSERTED.COL_B IN ('TEST1')
The error is that if I insert a different value in COL_B no rows are inserted.
Can you give me a solution?
thanks in advance

If you have more values than you want to put in a case statement, you can try using a table to store the banned words and the replacement for them. Then join to that in the insert, something like:
CREATE TRIGGER [dbo].[TEST_NAME_INS] ON [dbo].[TEST_A]
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO TEST_A
(COL_A
,COL_B)
SELECT
COL_A
,CASE WHEN b.banned is null then i.col_b
ELSE b.replacement
END
FROM inserted i
LEFT JOIN Banned b on i.col_B = b.banned

You need to modify your trigger.
CREATE TRIGGER [dbo].[TEST_NAME_INS] ON [dbo].[TEST_A]
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO TEST_A
(COL_A
,COL_B)
SELECT
COL_A
,CASE WHEN COL_B ='TEST1' THEN 'BANNED'
WHEN COL_B ='TEST12' THEN 'BANNED34'
ELSE COL_B END
FROM inserted

Related

Incrementing RECORD_ID When insterting records using a trigger

I am using a trigger to insert rows into a table using INSERT statement as below but when doing this the RECORD_ID number increments by 1 digit so all the records inserted have the same number..
This is what i'm using to increment the records from the trigger.
, ISNULL((
SELECT MAX([PROGRESS-RECID]) FROM [DBAdmin].[dbo].[ReTncyTransStatement]
),0) + 1 AS [PROGRESS-RECID]
This is what i'm using to load the data
;WITH TestTrans (
[ORG-CODE]
,[TNCY-SYS-REF]
,[TRANS-NO]
,[POSTING-YEAR]
,[POSTING-WEEK]
,[TRANS-YEAR]
,[TRANS-WEEK]
,[TRANS-DATE]
,[ACCOUNT-TYPE]
,[ACCOUNT-CODE]
,[COMMENT]
,[TRANS-AMT]
,[SOURCE]
,[CREATED-USER]
,[CREATED-DATE]
,[CREATED-TIME]
,[UPDATED-USER]
,[UPDATED-DATE]
,[UPDATED-TIME]
,[BATCH-NO]
,[BATCH-NO-TYPE]
,[SUSPENSE-REF]
,[REFERENCE]
,[MGT-AREA]
,[ANALYSIS-CODE]
)
AS (SELECT
[ORG-CODE]
,[TNCY-SYS-REF]
,[TRANS-NO]
,[POSTING-YEAR]
,[POSTING-WEEK]
,[TRANS-YEAR]
,[TRANS-WEEK]
,[TRANS-DATE]
,[ACCOUNT-TYPE]
,[ACCOUNT-CODE]
,[COMMENT]
,[TRANS-AMT]
,[SOURCE]
,[CREATED-USER]
,[CREATED-DATE]
,[CREATED-TIME]
,[UPDATED-USER]
,[UPDATED-DATE]
,[UPDATED-TIME]
,[BATCH-NO]
,[BATCH-NO-TYPE]
,[SUSPENSE-REF]
,[REFERENCE]
,[MGT-AREA]
,[ANALYSIS-CODE] from [SQLViewsPro2Live].[dbo].[RE-TNCY-TRANS] where [TRANS-DATE] between '2019-05-16 00:00:00.000' and '2019-05-17 00:00:00.000'
)
INSERT INTO [SQLViewsPro2Test].[dbo].[RE-TNCY-TRANS]
SELECT
[ORG-CODE]
,[TNCY-SYS-REF]
,[TRANS-NO]
,[POSTING-YEAR]
,[POSTING-WEEK]
,[TRANS-YEAR]
,[TRANS-WEEK]
,[TRANS-DATE]
,[ACCOUNT-TYPE]
,[ACCOUNT-CODE]
,[COMMENT]
,[TRANS-AMT]
,[SOURCE]
,[CREATED-USER]
,[CREATED-DATE]
,[CREATED-TIME]
,[UPDATED-USER]
,[UPDATED-DATE]
,[UPDATED-TIME]
,[BATCH-NO]
,[BATCH-NO-TYPE]
,[SUSPENSE-REF]
,[REFERENCE]
,[MGT-AREA]
,[ANALYSIS-CODE]
FROM TestTrans;
GO
Any fixes appreciated
Thanks,
Full description of problem available here: T-SQL : create trigger to copy new columns from one table to another and increment no
Make PROGRESS-RECID an IDENTITY column and it will auto-increment.
Based on the linked question, you can rewrite your trigger as following:
CREATE TRIGGER AddReTncyTransStatement
ON [SQLViewsPro2EOD].[dbo].[RE-TNCY-TRANS]
AFTER UPDATE, INSERT
AS
BEGIN
DECLARE #ORG_CODE INT,
#TNCY_SYS_REF INT,
#TRANS_NO INT;
DECLARE C CURSOR FAST_FORWARD FOR(
SELECT Inserted.[ORG-CODE],
Inserted.[TNCY-SYS-REF],
Inserted.[TRANS-NO]
FROM Inserted);
OPEN C;
FETCH NEXT FROM C
INTO #ORG_CODE,
#TNCY_SYS_REF,
#TRANS_NO;
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO [DBAdmin].[dbo].[ReTncyTransStatement]
(
[ORG-CODE],
[TNCY-SYS-REF],
[TRANS-NO],
[PROGRESS-RECID]
)
SELECT
#ORG_CODE,
#TNCY_SYS_REF,
#TRANS_NO,
ISNULL((SELECT MAX([PROGRESS-RECID]) FROM [DBAdmin].[dbo].[ReTncyTransStatement]),0) + 1 AS RECID;
FETCH NEXT FROM C
INTO #ORG_CODE,
#TNCY_SYS_REF,
#TRANS_NO
END;
CLOSE C;
DEALLOCATE C;
END;
Root of your problem:
When you use INSERT INTO ... SELECT(The one outside the trigger), trigger will be called once and the inserted table will contain all the records to be inserted. so the query inside the trigger will be run once, furthermore the SELECT MAX([PROGRESS-RECID]) will be calculated once. This means that if the inserted table contains 10 records, that are being inserted, then MAX(...) will be same for all of them!
How I Solved it:
Inside the trigger I used Cursor to iterate through the all records that are being inserted(For example 10 records), then in each iteration I insert one record to ReTncyTransStatement so the MAX(...) will be calculated and executed as expected.

SQL - How to create a trigger involving 2 separate tables?

Create an INSERT trigger called checkPub on the 'publishers' table to add a row into the 'pub_info' table
1) when a row is inserted into the 'publishers' table with the values of the pub_id inserted into the publishers table,
2) NULL in the logo column, and
3) the text 'Newbie' in the pr_info column.
4) In addition, print a message stating the pub_id along with '9991 Inserted into 'pub_info' table'.
INSERT INTO publishers( pub_id, pub_name, city, country )
VALUES( '9905', 'New Publisher', 'Vancouver', 'Canada' );
CREATE TRIGGER checkPub
BEFORE INSERT OR UPDATE ON
(Publishers P JOIN pub_info PI
ON
P.pub_id = PI.pub_id)
FOR EACH ROW
Not sure how to write the conditions after this.
You do not need any kind of looping here. You simply need a basic insert statement. Here is an example of the entire trigger.
CREATE TRIGGER checkPub ON Publishers after INSERT AS
set nocount on;
insert pub_info
(
pub_id
, logo
, pr_info
)
select i.pub_id
, null
, 'Newbie'
from inserted i;
Since this has the look of homework I will let you figure out the last requirement.

sql server how to default nvarhcar column to GUID if it's null or empty

If I have a nvarchar column in sql server 2012, how do I default the value to a GUID when the value is null or empty space?
To be more clear:
Not only it should work when people do:
INSERT INTO table(second_column) VALUES('test')
It should also work if people do:
INSERT INTO table(column_with_default, second_column) VALUES('', 'test')
I tried to set the default to
LEFT(NEWID(), 36)
but it doesn't work...
When I insert to the table with 'NULL' for that column, it's just NULL (same with '').
EDIT 2: According to your comments I change my answer
CREATE TABLE dbo.Test(ID NVARCHAR(MAX) NOT NULL DEFAULT NEWID()
,TestData NVARCHAR(MAX));
GO
CREATE TRIGGER dbo.TestTrigger ON dbo.Test
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO dbo.Test(ID,TestData)
SELECT CASE WHEN i.ID IS NULL OR i.ID='' THEN CAST(NEWID() AS NVARCHAR(MAX)) ELSE i.ID END,i.TestData
FROM inserted AS i;
END
GO
INSERT INTO dbo.Test(ID,TestData) VALUES(NULL,'test with NULL');
INSERT INTO dbo.Test(ID,TestData) VALUES('','test with EMPTY');
INSERT INTO dbo.Test(ID,TestData) VALUES('abc','test with real data');
SELECT * FROM Test;
GO
DROP TABLE dbo.Test;
The result
69604546-47BD-4E0D-9924-FAD39054BFFD test with NULL
D9F38DB0-1155-464B-89C7-43C2CE8381BF test with EMPTY
abc test with real data
You can use NEWID() in a Default Value constraint. If the field is not large enough then use LEFT(NEWID(),<field-length>) as the constraint expression.

Unable to set value based on INSERTED table in trigger

GOAL:I'm creating after insert trigger that should insert new record to OrderSuspendRule table based on rule in this table that was related with Promotion of which new version was created.
PROBLEM
I cannot set value to #SUS_ID. Select returns value but it isn't set to variable.
Sample insert:
INSERT INTO PromotionHeader (Guid,CreatedAt,UpdatedAt,IsActive,CompanyId,UpdatedById,CreatedById,Name,[Description],ValidFrom,ValidTo,BusinessUnitId,OfferId,[Version],StatusId,PreviousId)
select newid(),CreatedAt,UpdatedAt,1,CompanyId,UpdatedById,CreatedById,Name,[Description],ValidFrom,ValidTo,BusinessUnitId,OfferId,[Version]+1,StatusId,916 FROM PromotionHeader WHERE Id=916
Where PreviousId points to older version of promotion.
CREATE TRIGGER TRIG1 ON DBO.PromotionHeader
AFTER INSERT
AS
DECLARE #SUS_ID INT
SET #SUS_ID = (
SELECT Max(id)
FROM OrderSuspendRule
WHERE PromotionHeaderId = (
SELECT PreviousId
FROM inserted
WHERE ID = SCOPE_IDENTITY()
)
AND ISACTIVE=1
)
IF (#SUS_ID IS NOT NULL) --**VARIABLE IS ALWAYS NULL NO MATTER WHAT**
BEGIN
INSERT INTO OrderSuspendRule (
Guid
,CreatedAt
,UpdatedAt
,IsActive
,CompanyId
,UpdatedById
,CreatedById
,SuspendFrom
,SuspendTo
,PromotionHeaderId
,SuspendTypeId
,OfferItemId
)
SELECT NEWID()
,GETDATE()
,GETDATE()
,1
,CompanyId
,UpdatedById
,CreatedById
,SuspendFrom
,SuspendTo
,SCOPE_IDENTITY()
,SuspendTypeId
,OfferItemId
FROM OrderSuspendRule
WHERE id = #SUS_ID
END
Inside a for insert trigger, you can assume that all rows in the inserted table were inserted. There is no need to double check this with scope_identity().
To explain why scope_identity() is null, remember that scope_identity() returns the last inserted identity in the current scope. Since your trigger runs in its own scope, this will always be null, unless the trigger itself performs an insert.
Also, be aware that your trigger can be run for an insert of multiple rows. That means you can't expect only a single #sus_id, there might be many.

sql server merge with multiple insert when not matched

I'm using MERGE in my query and i'm making INSERT on clause WHEN NOT MATCHED THEN, but then i would like to get the inserted row identity and make another INSERT to some other table. Query for now is:
ALTER PROCEDURE [dbo].[BulkMergeOffers]
#data ImportDataType READONLY
AS
SET NOCOUNT ON;
DECLARE #cid int = 0
MERGE dbo.oferta AS target
USING #data AS source
ON (target.nr_oferty = source.nr_oferty)
WHEN NOT MATCHED THEN
INSERT (nr_oferty,rynek,typ_transakcji, typ_nieruchomosci,cena,powierzchnia, rok_budowy, wojewodztwo, miasto, dzielnica, ulica, opis, wspolrzedne, film, zrodlo, KontaktStore, data, forma_wlasnosci, stan_techniczny, liczba_pokoi, liczba_peter, pietro, material, kuchnia, pow_dzialki, typ_dzialki, woda,gaz, prad,sila, przeznaczenie,lokal_dane)
VALUES (source.nr_oferty,source.rynek,source.typ_transakcji, source.typ_nieruchomosci,source.cena,source.powierzchnia, source.rok_budowy, source.wojewodztwo, miasto, source.dzielnica, source.ulica, source.opis, source.wspolrzedne, source.film, source.zrodlo, source.KontaktStore, source.data, source.forma_wlasnosci, source.stan_techniczny, source.liczba_pokoi, source.liczba_peter, source.pietro, source.material, source.kuchnia, source.pow_dzialki, source.typ_dzialki, source.woda,source.gaz, source.prad,source.sila, source.przeznaczenie,source.lokal_dane);
So as you see i need to insert some values to the target table based on source data, then i need to take the insert identity and insert it into another table but also based on some source data, so something like that, just after the first insert:
SET #cid = SCOPE_IDENTITY();
if source.photo is not null
begin
insert into dbo.photos(offerID, file) values (#cid, source.photo);
end
But i can't assemble it, a have no access to the source no more, also if statement show error :
"the multi-part identifier
source.photo can not be bound"
but it is there. Just for clarity ImportDataType is a table-valued parameter.
Please HELP
If you don't need the WHEN MATCHED part of the MERGE statement in your query, there's no real reason to use MERGE. You could use INSERT with an outer join or NOT EXISTS statement.
In either case, you can use the OUTPUT clause to retrieve the inserted identity value an pass it on to a second query.
I've extended your example:
<stored procedure header - unchanged>
--declare a table variable to hold the inserted values data
DECLARE #newData TABLE
(nr_oferty int
,newid int
) -- I'm guessing the datatype for both columns
MERGE dbo.oferta AS target
USING #data AS source
ON (target.nr_oferty = source.nr_oferty)
WHEN NOT MATCHED THEN
INSERT (nr_oferty,rynek,typ_transakcji, typ_nieruchomosci,cena,powierzchnia, rok_budowy, wojewodztwo, miasto, dzielnica, ulica, opis, wspolrzedne, film, zrodlo, KontaktStore, data, forma_wlasnosci, stan_techniczny, liczba_pokoi, liczba_peter, pietro, material, kuchnia, pow_dzialki, typ_dzialki, woda,gaz, prad,sila, przeznaczenie,lokal_dane)
VALUES (source.nr_oferty,source.rynek,source.typ_transakcji, source.typ_nieruchomosci,source.cena,source.powierzchnia, source.rok_budowy, source.wojewodztwo, miasto, source.dzielnica, source.ulica, source.opis, source.wspolrzedne, source.film, source.zrodlo, source.KontaktStore, source.data, source.forma_wlasnosci, source.stan_techniczny, source.liczba_pokoi, source.liczba_peter, source.pietro, source.material, source.kuchnia, source.pow_dzialki, source.typ_dzialki, source.woda,source.gaz, source.prad,source.sila, source.przeznaczenie,source.lokal_dane)
OUTPUT inserted.nr_oferty, inserted.<tableId> INTO #newData;
-- replace <tableId> with the name of the identity column in dbo.oftera
insert into dbo.photos(offerID, file)
SELECT nd.newid, pt.photo
FROM #data AS pt
JOIN #newData AS nd
ON nd.nr_oferty = pt.nr_oferty
WHERE pt.photo IS NOT NULL

Resources