SQLServer Update Trigger with empty DELETED logical table - sql-server

I create a update trigger on a table to audit data changes...
the code used is:
ALTER TRIGGER dbo.Tg_table_upd ON dbo.table
FOR UPDATE
AS
DECLARE #DATA DATETIME= GETDATE();
DECLARE #USER VARCHAR(20);
SELECT
#USER = CONVERT(VARCHAR, context_info)
FROM master..sysprocesses
WHERE spid = ##SPID;
INSERT INTO table_LOG
SELECT
*,
#USER,
#DATA,
0
FROM deleted;
END;
Do some tests and its working...when I run a update in dbo.table I got 1 or more rows inserted in may audit table table_log.
But in a strange situation...when a java application run a specific update code (captured by SQL Profiler):
DECLARE #P1 INT;
SET #P1 = 68235;
EXEC sp_prepexec
#P1 OUTPUT,
N'#P0 nvarchar(4000),#P1 bigint,#P2 bigint,#P3 bigint,#P4 bigint,#P5 bigint,#P6 bigint,#P7 bigint,#P8 bigint,#P9 bigint,#P10 bigint,#P11 bigint,#P12 bigint,#P13 bigint,#P14 bigint,#P15 bigint,#P16 bigint,#P17 bigint,#P18 bigint,#P19 bigint,#P20 bigint,#P21 bigint,#P22 bigint,#P23 bigint,#P24 bigint,#P25 bigint,#P26 bigint,#P27 bigint,#P28 bigint,#P29 bigint,#P30 nvarchar(4000)',
N'update table set irc_status=#P0 where (irc_id in (#P1 , #P2 , #P3 , #P4 , #P5 , #P6 , #P7 , #P8 , #P9 , #P10 , #P11 , #P12 , #P13 , #P14 , #P15 , #P16 , #P17 , #P18 , #P19 , #P20 , #P21 , #P22 , #P23 , #P24 , #P25 , #P26 , #P27 , #P28 , #P29)) and irc_status=#P30 ',
N'XXX',
58074,
58079,
58082,
58086,
58091,
58095,
57880,
57879,
57874,
57873,
57953,
57959,
57954,
57960,
57785,
57790,
57779,
57784,
59113,
59110,
59116,
59119,
75840,
75851,
75843,
75852,
75834,
75844,
75842,
N'YYY';
SELECT
#P1;
The source table is updated (6 rows affected)...
But I get no rows in my audit table (table_log)
Looking foward in sql profiler... I can confirm the trigger was accioned but when run the statement
SELECT
*,
#USER,
#DATA,
0
FROM deleted;
SQL profiler shows 0 rows affected... So.. the update was commited...(6 ros affected... the trigger was fired... but have a empty "Deleted" Logical table...
Why??

Related

Adventure Works 2019: Adding New Person to Person.Person Table

Right now I am using 3 stored procedures to Add a person to the person.person table. I would like to cut this down to a single stored procedure to resolve this issue.
INSERT new GUID and DateModified to table Person.BusinessEntity
SELECT the auto generate BusinessEntityID form table Person.BusinessEntity
INSERT new Person to Person.Person Table
The Stored Procedures all use parameters which I pass via a C# application and I have confirmed that the a user is in fact added to the AdventureWorks2019 Db.
Procedure: Person.CreateNewBusinessEntity
INSERT INTO [Person].[BusinessEntity]
(
[BusinessEntity].rowguid
, [BusinessEntity].ModifiedDate
)
VALUES
(
#RowGUID
, GetDate()
)
Procedure: Person.GetBusinessEntityID
SELECT
[BusinessEntityID]
FROM
[AdventureWorks2019].[Person].[BusinessEntity]
WHERE [rowguid] = #RowGuid
Procedure: Person.CreateNewPerson
INSERT INTO [Person].[Person]
(
[BusinessEntityID]
,[PersonType]
,[NameStyle]
,[Title]
,[FirstName]
,[MiddleName]
,[LastName]
,[Suffix]
,[EmailPromotion]
,[AdditionalContactInfo]
,[Demographics]
,[rowguid]
,[ModifiedDate]
)
VALUES
(
#BusinessEntityID
, #PersonType
, #NameStyle
, #Title
, #FirstName
, #MiddleName
, #LastName
, #Suffix
, #EmailPromotion
, #AdditionalContactInfo
, #Demographics
, #RowGUID
, GetDate()
)
Any help here is appreciated. Thanks!
Thanks to HABO, I am now using this solution. Now I only need two procedures.
DECLARE #Inserted table ( [BusinessEntityID] int );
INSERT INTO [Person].[BusinessEntity]
(
[BusinessEntity].rowguid
, [BusinessEntity].ModifiedDate
)
OUTPUT inserted.[BusinessEntityID] INTO #Inserted([BusinessEntityID])
VALUES
(
#RowGUID
, GetDate()
)
The below answer shows you how to get the inserted id and add it to the next insert in side the Same SP.
USE AdventureWorks2012
GO
CREATE PROC CreateNewPerson
AS
BEGIN
DECLARE #OutputTbl TABLE ([BusinessEntityID] INT, ModifiedDate DATETIME)
DECLARE #BusinessEntityID AS INT
INSERT INTO [Person].[BusinessEntity]
(
[BusinessEntity].rowguid
, [BusinessEntity].ModifiedDate
)
--Get the output value inserted to a table.
OUTPUT inserted.[BusinessEntityID], inserted.ModifiedDate INTO
#OutputTbl([BusinessEntityID],[ModifiedDate])
VALUES
(
NEWID()
, GetDate()
)
--Assigned to a variable. You can get this using subquery as well inside the insert statment.
SELECT #BusinessEntityID = [BusinessEntityID] FROM #OutputTbl
INSERT INTO [Person].[Person]
(
[BusinessEntityID]
,[PersonType]
,[NameStyle]
,[Title]
,[FirstName]
,[MiddleName]
,[LastName]
,[Suffix]
,[EmailPromotion]
,[AdditionalContactInfo]
,[Demographics]
,[rowguid]
,[ModifiedDate]
)
VALUES
(
#BusinessEntityID
, #PersonType --These columns with # sign needed to be declared or supply values
, #NameStyle
, #Title
, #FirstName
, #MiddleName
, #LastName
, #Suffix
, #EmailPromotion
, #AdditionalContactInfo
, #Demographics
, NEWID() --This will generate a new GUID for each row.
, GetDate()
)
END
GO
Second way is using Scope_identity(). Replace the
"SELECT #BusinessEntityID = [BusinessEntityID] FROM #OutputTbl'
from below lines in the Sp will do the same thing for you.
SELECT #BusinessEntityID = SCOPE_IDENTITY() --[BusinessEntityID] FROM #OutputTbl
Select #BusinessEntityID

Stored procedure which writes xml into a DB, T-SQL

I am trying to write a stored procedure which writes xml into a DB, T-SQL.
Here is my sample xml (which will have a significant number of <RECORD>s in prod environment):
<?xml version="1.0" encoding="windows-1251"?>
<DATA FORMAT_VERSION="1.0">
<RECORD>
<NAME>МІЖНАРОДНА ГРОМАДСЬКА ОРГАНІЗАЦІЯ МІЖНАРОДНА АКАДЕМІЯ БІОЕНЕРГОТЕХНОЛОГІЙ</NAME>
<SHORT_NAME>МАБЕТ</SHORT_NAME>
<EDRPOU>00011601</EDRPOU>
<ADDRESS>01001, м.Київ, Шевченківський район, ВУЛИЦЯ ПРОРІЗНА, будинок 8, офіс 426</ADDRESS>
<STAN>зареєстровано</STAN>
</RECORD>
</DATA>
I pass the path to the xml file in the #pathToXml parameter.
Here is my stored procedure:
CREATE PROCEDURE [dbo].[LegalContractorsDataSynchronize]
(
#pathToXml varchar
)
AS
BEGIN
BEGIN TRANSACTION
DELETE FROM [dbo].[LegalContractors];
INSERT INTO [dbo].[LegalContractors]([Code], [ShortName], [Name], [LegalAddress], [Status])
SELECT CONVERT([Code], [ShortName], [Name], [LegalAddress], [Status])
FROM OPENROWSET(BULK, #pathToXml, SINGLE_CLOB) as x
COMMIT TRANSACTION
END
I am using Entity Framework to call the stored procedure. The call just happens (with no errors), but the DB is not updated. I am very sure that I mistyped something in the INSERT statement. I followed this example.
Could someone point out how could I fill the three columns in my DB using the data from the respective elements in xml? The columns are Code, ShortName, Name, LegalAddress and Status.
UPDATE
After the answer being posted I tried the suggested solution. I am getting the error:
Msg 102, Level 15, State 1, Procedure LegalContractorsDataSynchronize, Line 15 [Batch Start Line 0]
Incorrect syntax near '#pathToXml'.
Here is my code:
CREATE PROCEDURE [dbo].[LegalContractorsDataSynchronize]
(
#pathToXml varchar
)
AS
BEGIN
BEGIN TRANSACTION
DELETE FROM [dbo].[LegalContractors];
;WITH XmlFile (xmlData) AS
(
SELECT TRY_CAST(BulkColumn AS XML)
FROM OPENROWSET(BULK #pathToXml, SINGLE_BLOB) AS x
)
INSERT INTO [dbo].[LegalContractors] ([Code], [ShortName], [Name], [LegalAddress], [Status])
SELECT c.value('(EDRPOU/text())[1]','NVARCHAR(100)') AS [Code]
, c.value('(SHORT_NAME/text())[1]','NVARCHAR(512)') AS [ShortName]
, c.value('(NAME/text())[1]','NVARCHAR(2048)') AS [Name]
, c.value('(ADDRESS/text())[1]','NVARCHAR(2048)') AS [LegalAddress]
, c.value('(STAN/text())[1]','NVARCHAR(100)') AS [Status]
FROM XmlFile CROSS APPLY xmlData.nodes('/DATA/RECORD') AS t(c);
COMMIT TRANSACTION
END
Please try the following. To the best of my knowledge, OPENROWSET() doesn't accept file name parameter as a variable.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (
ID INT IDENTITY PRIMARY KEY,
Code NVARCHAR(50) NOT NULL,
ShortName NVARCHAR(100) NOT NULL,
[Name] NVARCHAR(100) NOT NULL,
LegalAddress NVARCHAR(100) NOT NULL,
[Status] NVARCHAR(50) NOT NULL
);
-- DDL and sample data population, end
-- Method #1
-- XML file is hardcoded
;WITH XmlFile (xmlData) AS
(
SELECT TRY_CAST(BulkColumn AS XML)
FROM OPENROWSET(BULK 'c:\...\Ukraine.xml', /*CODEPAGE = '65001',*/ SINGLE_BLOB) AS x
)
INSERT INTO #tbl (Code, ShortName, [Name], LegalAddress, [Status])
SELECT c.value('(EDRPOU/text())[1]','NVARCHAR(50)') AS [Code]
, c.value('(SHORT_NAME/text())[1]','NVARCHAR(100)') AS [ShortName]
, c.value('(NAME/text())[1]','NVARCHAR(100)') AS [Name]
, c.value('(ADDRESS/text())[1]','NVARCHAR(100)') AS [LegalAddress]
, c.value('(STAN/text())[1]','NVARCHAR(50)') AS [Status]
FROM XmlFile CROSS APPLY xmlData.nodes('/DATA/RECORD') AS t(c);
-- test
SELECT * FROM #tbl;
-- Method #2
-- dynamic XML file name as a parameter
DECLARE #xml XML
, #sql NVARCHAR(MAX)
, #fileName VARCHAR(256) = 'c:\...\Ukraine.xml';
SET #sql = N'SELECT #xmlOut = XmlDoc FROM OPENROWSET (BULK ' + QUOTENAME(#fileName,NCHAR(39)) + ', SINGLE_BLOB) AS Tab(XmlDoc)';
EXEC master.sys.sp_executesql #sql, N'#xmlOut XML OUTPUT', #xmlOut = #xml OUTPUT;
INSERT INTO #tbl (Code, ShortName, [Name], LegalAddress, [Status])
SELECT c.value('(EDRPOU/text())[1]','NVARCHAR(50)') AS [Code]
, c.value('(SHORT_NAME/text())[1]','NVARCHAR(100)') AS [ShortName]
, c.value('(NAME/text())[1]','NVARCHAR(100)') AS [Name]
, c.value('(ADDRESS/text())[1]','NVARCHAR(100)') AS [LegalAddress]
, c.value('(STAN/text())[1]','NVARCHAR(50)') AS [Status]
FROM #xml.nodes('/DATA/RECORD') AS t(c);
-- test
SELECT * FROM #tbl;

SQL Server : a strange thing happens with an Update inside a stored procedure

I have a stored procedure in SQL Server 2005 that the code inside is something like this :
select Unique_ID as ID
into tmp_table
from table1
Then, after some other statements, I do this update :
Update table1
set Flag = ‘Y’
Where Unique_ID in (select Unique_ID from tmp_table)
As you notice, I've purposely mistaken ID by Unique_ID (the column name in tmp_table) when I wanted to update.
Now the bizarre thing that happens, is that SQL Server doesn’t show an error when I execute the stored procedure.
It ignores the line where the error is :
Where Unique_ID in (select Unique_ID from tmp_table)
And runs just this :
Update table1 set
Flag = ‘Y’
Any ideas?
Thanks a lot.
UPDATE:
Here is the stored procedure code :
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
GO
CREATE PROCEDURE [dbo].[MyProc]
AS
BEGIN
SET NOCOUNT ON
DECLARE #date VARCHAR(20)
SET #date = REPLACE(CONVERT(VARCHAR(8), GETUTCDATE(), 3), '/', '')
+ REPLACE(CONVERT(VARCHAR(8), GETUTCDATE(), 108), ':', '')
DECLARE #PATH AS VARCHAR(500)
SET #PATH = 'C:\MyPath\'
BEGIN TRY
EXEC master.dbo.xp_create_subdir #PATH
END TRY
BEGIN CATCH
PRINT 'FOLDER NOT CREATED'
END CATCH
IF EXISTS (SELECT name FROM sys.tables WHERE name = 'TMP_TABLE')
DROP TABLE TMP_TABLE
SELECT
UNIQUE_ID [Unique ID] ,
'col1' COL1,
'col2' COL2,
'col3' COL3,
'col4' COL4
INTO
TMP_TABLE
FROM
TABLE1
WHERE
Flag IN 'N'
--Try to generate file, If there was any problem, return from the SP => no update
BEGIN TRY
DECLARE #QUERY VARCHAR(MAX)
SET #QUERY = 'EXEC master..xp_cmdshell ''sqlcmd -E -s"," -W -h-1 -Q "SET NOCOUNT ON;SELECT * FROM dbo.TMP_TABLE" | findstr /V /C:"-" /B > '
+ #PaTH + '\FileName_' + #date + '.csv'',no_output;'
EXEC(#QUERY)
END TRY
BEGIN CATCH
PRINT 'Exception during file generation'
RETURN
END CATCH
PRINT 'File Generated'
UPDATE TABLE1
SET Flag = 'Y',
MODIFICATION_DATE = GETDATE()
WHERE
UNIQUE_ID IN (SELECT UNIQUE_ID FROM TMP_TABLE)
BEGIN TRY
DROP TABLE dbo.TMP_TABLE
PRINT 'TMP table dropped'
END TRY
BEGIN CATCH
PRINT 'TMP table not dropped'
END CATCH
END
GO
The problem is on this line:
WHERE UNIQUE_ID IN (SELECT **UNIQUE_ID** FROM TMP_TABLE)
I should replace UNIQUE_ID with [UNIQUE ID]
But SQL Server doesn't throw an error, it simply updates all records.
And here is the structure of table1 :
CREATE TABLE [dbo].[TABLE1]
(
UNIQUE_ID int NOT NULL IDENTITY(1, 1), --Primary key
Flag [varchar] (1) ,
MODIFICATION_DATE datetime,
)
I assume you had a typo in your query. Your tables look like that?
create table1
( Unique_ID int
, Flag char(1)
, ...
);
create tmp_table
( [Unique ID] int primary key
, ...
);
in that case your query is:
Update table1 t1 set
Flag = ‘Y’
Where t1.Unique_ID in (select t1.Unique_ID from tmp_table)
which is true except your id is null. you just compare the Unique_ID from table1 with itself.
Try to explicitly refer to the column to which you want to compare, by using the table name as well:
UPDATE TABLE1
SET Flag = 'Y',
MODIFICATION_DATE = GETDATE()
WHERE
UNIQUE_ID IN (SELECT TMP_TABLE.UNIQUE_ID FROM TMP_TABLE)
Confusion arises because there's a column named UNIQUE_ID on both tables, so by fully-qualifying it with the table name in the subselect, you can be 100% sure that you are referring to the right column.

Insert a row to SQL table

I am writing a store procedure in T-SQL which inserts a row to the table, based on parameters
#UserName ,#CompanyName ,#RestName,#Desc
INSERT INTO Orders(UserId,CompanyId,RestId)
SELECT UserNames.Id,CompanyNames.Id,RestNames.Id FROM UserNames,CompanyNames,RestNames
WHERE
UserNames.Name = #UserName AND
CompanyNames.Name = #CompanyName AND
RestNames.Name = #RestName
Besides the insert to the 3 columns above,I also want to insert the #Desc value.
I tried :
INSERT INTO Orders(UserId,CompanyId,RestId,Desc)
VALUES(
(SELECT UserNames.Id,CompanyNames.Id,RestNames.Id FROM UserNames,CompanyNames,RestNames
WHERE
UserNames.Name = #UserName AND
CompanyNames.Name = #CompanyName AND
RestNames.Name = #RestName),#Desc)
Only one expression can be specified in the select list when the subquery is not introduced with EXISTSt-
It doesn`t work giving the following error:
#UserName ,#CompanyName ,#RestName,#Desc
INSERT INTO Orders(UserId,CompanyId,RestId, Desc_Column)
SELECT UserNames.Id,CompanyNames.Id,RestNames.Id , #Desc --<-- Just SELECT that variable
FROM UserNames,CompanyNames,RestNames -- in your select statement.
WHERE UserNames.Name = #UserName
AND CompanyNames.Name = #CompanyName
AND RestNames.Name = #RestName
Retrieve ID Values Inserted
DECLARE #t TABLE (ID INT); --<-- Declare a table variable
INSERT INTO Orders(UserId,CompanyId,RestId, Desc_Column)
OUTPUT Inserted.ID INTO #t --<-- use OUTPUT, get values from INSERTED Table
SELECT UserNames.Id,CompanyNames.Id,RestNames.Id , #Desc --and insert them into your table variable
FROM UserNames,CompanyNames,RestNames
WHERE UserNames.Name = #UserName
AND CompanyNames.Name = #CompanyName
AND RestNames.Name = #RestName
/*At last just simply select from that table variable to get the inserted IDs*/
SELECT * FROM #t

little problem with mssql cursor, insert in temp table within the cursor

i'm having a little trouble with my stored procedure.
I've written a stored procedure where i'm using a cursor.
Every thing works fine till the place where i'm inserting values from the cursor to the temp table.
here is the error
Msg 156, Level 15, State 1, Procedure ors_DailyReportMessageStatus, Line 36
Incorrect syntax near the keyword 'where'.
and here is the code
ALTER PROCEDURE [dbo].[ors_DailyReportMessageStatus]
-- Add the parameters for the stored procedure here
#startDate datetime, #endDate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
DECLARE #num int;
DECLARE #stat varchar(20);
DECLARE #statusCursor CURSOR
SET #statusCursor = CURSOR FOR
select count(ms.status) as message, ms.status from message_status ms JOIN [message] m on m.id=ms.message_id
where (m.ADDED_ON >= #startDate AND m.ADDED_ON < #endDate) GROUP BY ms.status
SET NOCOUNT ON;
if object_id('tempdb..#tempdailystatus') is not null
begin
drop table #tempdailystatus
end
CREATE TABLE #tempdailystatus(id int identity, total int , [status] varchar(20));
insert into #tempdailystatus ([status])
select distinct([status]) from message_status;
open #statusCursor
fetch next from #statusCursor into #num, #stat;
while ##FETCH_STATUS = 0
begin
-- this is where the error is
insert into #tempdailystatus (total) values (#num) where id = (select id from #tempdailystatus where [status] = #stat)
-- this were just to see whether the cursor is ok. and it is
--print #stat
--print #num ;
fetch next from #statusCursor into #num,#stat
end
close #statusCursor
deallocate #statusCursor
-- Insert statements for procedure here
-- SELECT * from #tempdailystatus
drop table #tempdailystatus
END
Am I possibly ignoring something? it seems like i'm forgetting something.
Thanks you for reading this and for giving suggestion .will appreciate it ^_^
try replacing:
insert into #tempdailystatus (total) values (#num) where id = (select id from #tempdailystatus where [status] = #stat)
with:
If Exists(Select 1 From #tempdailystatus where [status] = #stat)
Begin
insert into #tempdailystatus (total) Values(#num)
End
I made some assumptions about your logic, so you may need to adjust accordingly.

Resources