I'm trying to find out what is updating the value of a column and i have very little knowledge of the application. At a quick glance I've noticed about 90% of the applications business logic is handled on the database. Needless to say the depth of SP's, functions, and triggers is crazy.
I'd like to create a trigger on the table in question that will log the SQL that affected the table. What SQL could be used to grab the executed SQL in the context of the table being updated?
Details:
MS SQL Server 2008
Thanks!!
I realise this issue has already been resolved but I was interested in how it could be resolved using SQL Server 2008 extended events. This is my first play with XEvents so I'm sure there's lots to improve!
Script to setup test Database
CREATE TABLE [dbo].[TableWithMysteryUpdate](
[Period] [int] NOT NULL,
[ColumnThatWillBeUpdated] [int] NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[TableWithMysteryUpdate] ([Period], [ColumnThatWillBeUpdated]) VALUES (1, 20)
INSERT [dbo].[TableWithMysteryUpdate] ([Period], [ColumnThatWillBeUpdated]) VALUES (2, 23)
GO
CREATE TABLE [dbo].[TestTable](
[foo] [int] IDENTITY(1,1) NOT NULL,
[bar] [nchar](10) NOT NULL,
CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED
(
[foo] ASC
)
)
GO
CREATE TRIGGER [dbo].[triggerCausingMysteryUpdate]
ON [dbo].[TestTable]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE [dbo].[TableWithMysteryUpdate]
SET [Period] = [Period]+1
END
GO
CREATE PROCEDURE [dbo].[Proc4]
AS
BEGIN
INSERT INTO [dbo].[TestTable]
(
[bar])
VALUES
('Test')
END
GO
CREATE PROCEDURE [dbo].[Proc3]
AS
BEGIN
EXEC dbo.Proc4
END
GO
CREATE PROCEDURE [dbo].[Proc2]
AS
BEGIN
EXEC dbo.Proc3
END
GO
CREATE PROCEDURE [dbo].[Proc1]
AS
BEGIN
EXEC dbo.Proc2
END
So the scenario is that TableWithMysteryUpdate is being updated but I'm not sure by what. I'll add an update trigger that does nothing in order to be able to filter on this object.
CREATE TRIGGER [dbo].[triggerAfterUpdate]
ON [dbo].[TableWithMysteryUpdate]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
END
Then run the script to create the XEvents Session, fire the procedure that will eventually down the call stack cause the Update to occur, and then stop the session.
USE TestDB
DECLARE #DynSql nvarchar(max)
SET #DynSql = '
IF EXISTS(SELECT * FROM sys.server_event_sessions WHERE name=''test_trace'')
DROP EVENT SESSION [test_trace] ON SERVER;
CREATE EVENT SESSION [test_trace]
ON SERVER
ADD EVENT sqlserver.sql_statement_completed(
ACTION (package0.callstack, sqlserver.session_id, sqlserver.sql_text, sqlserver.tsql_stack)
WHERE (object_id = ' + cast(object_id('[dbo].[triggerAfterUpdate]') as varchar(10)) + ')
)
,
ADD EVENT sqlserver.sp_statement_completed(
ACTION (package0.callstack, sqlserver.session_id, sqlserver.sql_text, sqlserver.tsql_stack)
WHERE (object_id = ' + cast(object_id('[dbo].[triggerAfterUpdate]') as varchar(10)) + ')
)
ADD TARGET package0.asynchronous_file_target
(set filename = ''c:\temp\test_trace.xel'' , metadatafile = ''c:\temp\test_trace.xem'')
ALTER EVENT SESSION [test_trace] ON SERVER STATE = START
'
EXEC sp_executesql #DynSql
GO
EXEC dbo.Proc1
GO
ALTER EVENT SESSION [test_trace] ON SERVER STATE = STOP
The trace data can be read with
SELECT CONVERT (XML, event_data) AS data
FROM sys.fn_xe_file_target_read_file ('C:\Temp\test_trace*.xel', 'C:\Temp\test_trace*.xem', NULL, NULL)
The call stack part is
<action name="tsql_stack" package="sqlserver">
<value><frame level='1' handle='0x03000800E8EA0D0612E4EB00A59D00000000000000000000' line='6' offsetStart='228' offsetEnd='264'/>
<frame level='2' handle='0x03000800921155002C81E700A59D00000000000000000000' line='8' offsetStart='258' offsetEnd='398'/>
<frame level='3' handle='0x03000800CB3549012F81E700A59D00000100000000000000' line='5' offsetStart='90' offsetEnd='284'/>
<frame level='4' handle='0x03000800045A3D022F81E700A59D00000100000000000000' line='5' offsetStart='90' offsetEnd='120'/>
<frame level='5' handle='0x030008003D7E31033081E700A59D00000100000000000000' line='5' offsetStart='90' offsetEnd='120'/>
<frame level='6' handle='0x0300080076A225043081E700A59D00000100000000000000' line='5' offsetStart='90' offsetEnd='120'/>
<frame level='7' handle='0x010008002E775203603D9A0D000000000000000000000000' line='2' offsetStart='4' offsetEnd='-1'/></value>
<text />
</action>
Joining onto the DMVs
WITH CapturedResults AS
( SELECT data.value ( '(/event/#timestamp)[1]', 'DATETIME') AS [TIME],
data.value ( '(/event/data[#name=''cpu'']/value)[1]', 'INT') AS [CPU (ms)],
CONVERT (FLOAT, data.value ('(/event/data[#name=''duration'']/value)[1]', 'BIGINT')) / 1000000 AS [Duration (s)],
data.value ( '(/event/action[#name=''sql_text'']/value)[1]', 'VARCHAR(MAX)') AS [SQL STATEMENT],
CAST(data.value('(/event/action[#name="tsql_stack"]/value)[1]','varchar(MAX)') AS XML) AS [stack_xml]
FROM (SELECT CONVERT (XML, event_data) AS data
FROM sys.fn_xe_file_target_read_file ('C:\Temp\test_trace*.xel', 'C:\Temp\test_trace*.xem', NULL, NULL)
)
entries
)
,
StackData AS
( SELECT frame_xml.value('(./#level)', 'int') AS [frame_level],
frame_xml.value('(./#handle)', 'varchar(MAX)') AS [sql_handle],
frame_xml.value('(./#offsetStart)', 'int') AS [offset_start],
frame_xml.value('(./#offsetEnd)', 'int') AS [offset_end]
FROM CapturedResults CROSS APPLY stack_xml.nodes('//frame') N (frame_xml)
)
SELECT sd.frame_level,
object_name(st.objectid, st.dbid) AS ObjectName,
SUBSTRING(st.text, (sd.offset_start/2)+1, ((
CASE sd.offset_end
WHEN -1
THEN DATALENGTH(st.text)
ELSE sd.offset_end
END - sd.offset_start)/2) + 1) AS statement_text,
qp.query_plan,
qs2.creation_time,
qs2.last_execution_time,
qs2.execution_count
FROM StackData AS sd CROSS APPLY sys.dm_exec_sql_text(CONVERT(VARBINARY(MAX),sd.sql_handle,1)) AS st
LEFT OUTER JOIN sys.dm_exec_query_stats qs2
ON qs2.sql_handle = CONVERT(VARBINARY(MAX),sd.sql_handle,1) OUTER APPLY sys.dm_exec_query_plan(CONVERT(VARBINARY(MAX),qs2.plan_handle,1)) AS qp
gives results (showing the whole tsql call stack)
Besides using triggers that will be fired when a data change occurs, you can use SQL Server traces and analyse them in SQL Profiler, or a third party auditing tool that tracks executed code for DML changes.
Using ApexSQL Comply you can narrow down the auditing only the the specific database object (table in this case) and event type.
The reports show various useful info, including the SQL statement executed that initiated the change.
Disclaimer: I work for ApexSQL as a Support engineer
My Solution
I added a trigger on the table in question that logged information i narrowed down via timestamps from sys.dm_exec_sql_text AND sys.dm_exec_query_stats. This quickly nailed down what i was looking for. Turns out there were a few triggers i didn't know about that were updating data after a UPDATE.
SELECT
qStats.last_execution_time AS [ExecutedAt],
qTxt.[text] AS [Query], qTxt.number
FROM
sys.dm_exec_query_stats AS qStats
CROSS APPLY
sys.dm_exec_sql_text(qStats.sql_handle) AS qTxt
WHERE
qTxt.[dbid] = #DbId
AND qTxt.[text] like '%UPDATE%'
AND qStats.last_execution_time between #StartExecutionSearchTime and #EndExecutionSearchTime
ORDER BY
qStats.last_execution_time DESC
Please vote for this Microsoft Connect item, and have a look at this call stack workaround.
SQL Server 2008 introduced a new feature called Change Data Capture (CDC), rather than use triggers. Read more about it here.
Related
I've got a problem and a working solution to update viewvounts on some posts on a website I'm building but I'm looking for the fastest possible way and it feels very long way around
I want to be able to get posts based on lots of different criteria, such as who posted it, last 20 posts, top 20 containing some search text etc but with 2 lots of extra information INNER JOINED which is all easy enough but as I have no interaction other than selecting by some criteria I cant see a way to update the viewcounts for each.
Hopefully if the site goes well this will be heavily used so I am looking to do it as quickly as possible.
The best working solution I have so far is to;
Open the connection
Get the posts I want
Process them onto the web page making a string of all the ID numbers
run another stored procedure to update the viewcounts of those numbers
Close the connection
Am I missing something stupidly simple here?
the [Posts] table is simple;
[PostID] BIGINT
[PostUserID] INT
[PostGroupID] INT
[PostType] INT
[PostText] NVARCHAR(500)
[PostLinkText] NVARCHAR(250)
[Vewcount] INT
[Likes] INT
[comments] INT
The code I'm using to update the views is like this:
DECLARE #ViewedPosts NVARCHAR(MAX) = '1000|22|13|1000|400101011|22|13|1000|22|13|400101011'
SET NOCOUNT ON
DECLARE #Temp TABLE
(
[PostID] BIGINT
)
INSERT INTO #Temp
SELECT [Value] AS [PostID] FROM dbo.SPLIT(#ViewedPosts, '|')
DECLARE #PID BIGINT
WHILE EXISTS(SELECT * FROM #Temp)
BEGIN
SELECT TOP 1 #PID = [PostID] FROM #Temp
-- UPDATE [Posts] SET [Viewcount]=[Viewcount]+1 WHERE [PostID]=#PID --
SELECT [PostID] FROM #Temp WHERE [PostID]=#PID
DELETE #Temp WHERE [PostID]= #PID
END
SET NOCOUNT OFF
the dbo.SPLIT just makes a single column table of all the postID's from the viewed posts string.
CREATE FUNCTION [dbo].[Split]
(
#String NVARCHAR(4000),
#Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
WITH Split(stpos,endpos)
AS(
SELECT 0 AS stpos, CHARINDEX(#Delimiter,#String) AS endpos
UNION ALL
SELECT endpos+1, CHARINDEX(#Delimiter,#String,endpos+1)
FROM Split
WHERE endpos > 0
)
SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
'value' = SUBSTRING(#String,stpos,COALESCE(NULLIF(endpos,0),LEN(#String)+1)-stpos)
FROM Split
)
GO
I've done the usual scouring google and stackoverflow but all I am finding is different solutions that work out more or less what I've already got.
UPDATE: Working solution:
DECLARE #Temp TABLE ( [PostIDt] BIGINT )
INSERT INTO #Temp SELECT [PostID] AS [PostIDt] FROM [Posts] WITH(NOLOCK) ORDER BY [POSTID] DESC;
UPDATE [Posts] SET [ViewCount]=[ViewCount]+1 WHERE [PostId] IN (SELECT [PostIDt] AS [PostId] FROM #Temp);
SELECT * FROM #Temp INNER JOIN [Posts] ON [PostIDt] = [Posts].[PostID];
And now to updating part, the split string contains the same Id multiple times, thus I assume you want to increase by how many times an Id occurs there, not just 1:
DECLARE #ViewedPosts NVARCHAR(MAX) =N'1000|22|13|1000|400101011|22|13|1000|22|13|400101011';
SET NOCOUNT ON;
UPDATE [Posts]
SET [ViewCount]=[ViewCount]+tmp.Views
FROM
(
SELECT
s, COUNT(*) AS Views
FROM dbo.ufn_SplitString(#ViewedPosts, '|')
GROUP BY s
) tmp
WHERE [postId]=tmp.s;
SET NOCOUNT OFF;
EDIT: Getting the posts from SQL server and update all in one call:
UPDATE [Posts]
SET [ViewCount]=[ViewCount]+1
WHERE [postId] in (SELECT TOP(20) PostId
FROM [Posts]
ORDER BY [POSTID] DESC);
OK you didn't tag the database but from the code it is SQL server (not sure of the version, I would assume not the latest and even may be an older version).
Let's start with splitting the string. It is still not clear to me how you are generating that string. You're saying you construct it using reader("PostId") in webpage. That reader might be the result of an ExecuteReader, meaning you are getting it from the database? If so, getting PostIds from database and then sending back might be unnecessary trip.
For the moment, the source of it is not clear, so I would assume it is needed to be constructed as a string as you did and then sent to database to be split.
Splitting the string is the first performance point. For small strings as in your example, it may not be important taking a fraction of time with the Split() function you have. However, for large strings, that code is slow and may even time out and fail if the string is large enough. I would suggest changing that to a CLR function.
You can use this code to do that (you may try this on a new test database if you will before applying to yours):
First if CLR is not enabled, it needs to be enabled:
EXEC sp_configure 'clr enabled', '1';
RECONFIGURE;
And execute this code to add the function (SQL 2017 and later, for older versions, dbo.sp_add_trusted_assembly doesn't exists, instead SET TRUSTWORTHY ON is a way to do it - not sure if that would be a recommended thing to do):
IF EXISTS
(
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[ufn_SplitString]')
AND type IN ( N'FN', N'IF', N'TF', N'FS', N'FT' )
)
DROP FUNCTION [dbo].[ufn_SplitString];
GO
IF EXISTS
(
SELECT *
FROM sys.[assemblies] AS [a]
WHERE [a].[name] = 'SQLUtils'
AND [a].[is_user_defined] = 1
)
DROP ASSEMBLY SqlUtils;
GO
DECLARE #ta VARBINARY(64);
SELECT #ta = hash
FROM sys.trusted_assemblies AS ta
WHERE description = N'SQL CLR Utils';
IF #ta IS NOT NULL
BEGIN
EXEC dbo.sp_drop_trusted_assembly #hash = #ta;
END;
GO
EXEC dbo.sp_add_trusted_assembly #hash = 0xCEB076E6BB8C51E08743269F6BA1AC0BB3C6E2E25B78085918DBAEE60BFC88ED45EEE861CC571DBDEDF0AD7252AEF9D1DD51DB94E6E46C69F24D0C518A8E2D98,
#description = N'SQL CLR Utils';
CREATE ASSEMBLY SQLUtils AUTHORIZATION [dbo]
FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000\
800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A\
2400000000000000504500004C01030061F3D4630000000000000000E00022200B013000001600000006000000000000BA3400000020000000400000\
0000001000200000000200000400000000000000060000000000000000800000000200003AD200000300608500001000001000000000100000100000\
00000000100000000000000000000000683400004F000000004000007803000000000000000000000000000000000000006000000C00000030330000\
1C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000\
082000004800000000000000000000002E74657874000000C0140000002000000016000000020000000000000000000000000000200000602E727372\
6300000078030000004000000004000000180000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000001C0000\
00000000000000000000000040000042000000000000000000000000000000009C340000000000004800000002000500982200001810000009000000\
000000000000000000000000B03200008000000000000000000000000000000000000000000000000000000000000000000000003602036F1B00000A\
28020000062A5A1FFE730800000625027D0700000425037D090000042A4E0302741F000001281C00000A731D00000A512A1E02281E00000A2A2E7306\
00000680010000042A8203281F00000A2D16036F2000000A16310D03166F2100000A282200000A2A162A6602281E00000A02037D0300000402282300\
000A7D050000042A1B3002001B00000001000011027B030000040A061FFD2E040617330A00DE0702280B000006DC2A00011000000200110002130007\
000000001B300300E800000002000011027B030000040B072C0E07173BA8000000160ADDCE00000002157D03000004027B06000004282400000A3AAC\
000000027B080000048E2D36027B060000047201000070282500000A7E02000004252D17267E01000004FE0607000006732600000A25800200000428\
0100002B2B14027B06000004027B08000004176F2800000A0D090C02086F1800000A7D0A000004021FFD7D030000042B28027B0A0000046F1500000A\
13040211047D0400000402177D03000004170ADE2D021FFD7D03000004027B0A0000046F1400000A2DCB02280B00000602147D0A000004160ADE0702\
2809000006DC062A0110000004000000DFDF0007000000006E02157D03000004027B0A0000042C0B027B0A0000046F1300000A2A1E027B040000042A\
1A732900000A7A00133002004300000003000011027B030000041FFE3318027B05000004282300000A330B02167D03000004020A2B07167308000006\
0A06027B070000047D0600000406027B090000047D08000004062A1E02280F0000062A0042534A4201000100000000000C00000076342E302E333033\
31390000000005006C00000044050000237E0000B0050000D006000023537472696E677300000000800C00000800000023555300880C000010000000\
2347554944000000980C00008003000023426C6F6200000000000000020000015717A20B090A000000FA013300160000010000002600000004000000\
0A000000100000000800000005000000290000001A000000030000000100000002000000020000000700000003000000010000000400000002000000\
010000000000800301000000000006009E02B60406001F03B6040600870184040F00D60400000600AF01940306008102940306004D02940306000603\
94030600BE0294030600D70294030600E401940306009B0197040600790197040600300294030600FF013D0306006B058D030A006C02D8030A00D700\
D803060009012205060021018D030600C601B60406002A008C000600F2028D030A005205E50406005E01B60406005F008D03060015018D030600F303\
2205060038008C00060018028404060066038D030A005703E5040600CA038D030600B9058D030E00AD06030512000A01BE03060035058D030600A603\
8D03000000006A000000000001000100010010007803FA044100010001000321100088000000410001000500030110001B0000004100030008003600\
66006E01160001007201010053017A01010097067D010100C2007A01010069057D0106007D047D0101006005800106005B0580010100460084015020\
00000000960061038B0101005E20000000009100CF03920103007520000000009600F9009D0105008920000000008618700406000700912000000000\
91187604A501070089200000000086187004060007009D200000000083000A00A9010700BE20000000008618700401000800D82000000000E1013801\
06000900102100000000E101A406200009001422000000008100510006000900302200000000E1092A06AE010900382200000000E101720506000900\
302200000000E1096C062F000900402200000000E101FF03B20109008F2200000000E101430442000900000001006905000002006005000001006905\
00000200600500000100BC0302000200A500000001007B0400000100530104000A0004004D000400060004006D000400710009007004010011007004\
0600190070040A0029007004100031007004100039007004100041007004100049007004100051007004100059007004100061007004150069007004\
1000710070041000790070041000890070040600A90070041A00B90070040600C90070040600D9004B010600E100A40620000C008B062A00E1009105\
0600E1008B062F00140062043900990062044200F10070040600F900B3064700010197054C00C10070045300810070040600F900E6005A00F9006D03\
5F00F900480563000901A30568001101A7006D00F900BF065A001901B30585001C0070049300210126019900F900B305B40031017004060020007B00\
A0022E000B00C2012E001300CB012E001B00EA012E002300F3012E002B0001022E00330001022E003B0001022E004300F3012E004B0007022E005300\
01022E005B0001022E0063001F022E006B0049022E0073005602400083005503630093007A03830093007A0384008B007A030001D3007A032001D300\
7A038001D3007A03A001D3007A03C001D3007A03E001D3007A030002D3007A0371007500BE00040001000000C505BA0100000306BE0102000C000300\
02000E000500040012002700040014002900040018002B0004001A002D0004001C002F0004001E003100040020003300240033008C00048000000100\
00000000000001000000CC00FA040000040000000000000000000000C3007F0000000000040000000000000000000000C30073000000000004000000\
0000000000000000C3008D0300000000040000000000000000000000C3002C010000000003000200040002004F00B00000000000003C3E395F5F315F\
30003C53706C69747465723E625F5F315F30003C53706C69747465723E645F5F310049456E756D657261626C6560310049456E756D657261746F7260\
31003C3E375F5F7772617031003C3E6D5F5F46696E616C6C79310046756E636032003C3E39003C4D6F64756C653E0053797374656D2E44617461006D\
73636F726C6962003C3E630053797374656D2E436F6C6C656374696F6E732E47656E65726963006765745F43757272656E744D616E61676564546872\
6561644964003C3E6C5F5F696E697469616C546872656164496400446174614163636573734B696E640049734E756C6C4F7257686974655370616365\
0046696C6C537472696E675461626C650049456E756D657261626C650049446973706F7361626C6500547970650057686572650053797374656D2E43\
6F72650053797374656D2E49446973706F7361626C652E446973706F7365003C3E315F5F737461746500436F6D70696C657247656E65726174656441\
747472696275746500477569644174747269627574650044656275676761626C6541747472696275746500436F6D56697369626C6541747472696275\
746500417373656D626C795469746C65417474726962757465004974657261746F7253746174654D616368696E654174747269627574650041737365\
6D626C7954726164656D61726B417474726962757465005461726765744672616D65776F726B41747472696275746500446562756767657248696464\
656E41747472696275746500417373656D626C7946696C6556657273696F6E41747472696275746500417373656D626C79436F6E6669677572617469\
6F6E4174747269627574650053716C46756E6374696F6E41747472696275746500417373656D626C794465736372697074696F6E4174747269627574\
6500436F6D70696C6174696F6E52656C61786174696F6E7341747472696275746500417373656D626C7950726F647563744174747269627574650041\
7373656D626C79436F7079726967687441747472696275746500506172616D417272617941747472696275746500417373656D626C79436F6D70616E\
794174747269627574650052756E74696D65436F6D7061746962696C6974794174747269627574650053797374656D2E52756E74696D652E56657273\
696F6E696E670053716C537472696E670053706C6974537472696E67006765745F4C656E6774680053716C5574696C0053514C5574696C732E646C6C\
0053797374656D0053797374656D2E5265666C656374696F6E004E6F74537570706F72746564457863657074696F6E006F0053797374656D2E4C696E\
7100436861720053706C6974746572004D6963726F736F66742E53716C5365727665722E5365727665720049456E756D657261746F72005379737465\
6D2E436F6C6C656374696F6E732E47656E657269632E49456E756D657261626C653C53797374656D2E537472696E673E2E476574456E756D65726174\
6F720053797374656D2E436F6C6C656374696F6E732E49456E756D657261626C652E476574456E756D657261746F72002E63746F72002E6363746F72\
003C3E335F5F730053797374656D2E446961676E6F73746963730053797374656D2E52756E74696D652E496E7465726F705365727669636573005379\
7374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F6465730053797374656D2E446174612E53716C\
54797065730053514C5574696C730053797374656D2E546578742E526567756C617245787072657373696F6E730053797374656D2E436F6C6C656374\
696F6E7300537472696E6753706C69744F7074696F6E73006765745F43686172730053716C4368617273003C3E335F5F736570617261746F7273004F\
626A6563740053797374656D2E436F6C6C656374696F6E732E49456E756D657261746F722E5265736574006F705F496D706C696369740049734C6574\
7465724F7244696769740053706C697400456E7669726F6E6D656E740053797374656D2E436F6C6C656374696F6E732E47656E657269632E49456E75\
6D657261746F723C53797374656D2E537472696E673E2E43757272656E740053797374656D2E436F6C6C656374696F6E732E49456E756D657261746F\
722E43757272656E740053797374656D2E436F6C6C656374696F6E732E47656E657269632E49456E756D657261746F723C53797374656D2E53747269\
6E673E2E6765745F43757272656E740053797374656D2E436F6C6C656374696F6E732E49456E756D657261746F722E6765745F43757272656E74003C\
3E325F5F63757272656E74004D6F76654E65787400526567657800546F4368617241727261790049734E756C6C4F72456D7074790000000000055C00\
62000000233D59D645D99849B7DE049542552E5000042001010803200001052001011111042001010E04200101020520010112510320000205151275\
010E04200013000320001C05151259010E08200015127501130004200012710420001D030600011180810E06200101118081040001020E0320000804\
20010308040001020303000008030701080F07050208151259010E151259010E0E0600021D0E0E0E06151269020E02052002011C1816100102151259\
011E00151259011E00151269021E0002030A010E0920021D0E1D03118095040701121008B77A5C561934E08980A00024000004800000940000000602\
000000240000525341310004000001000100858173EEBF9F0EA6C8BFB7F1F3E5D6238024C53672D0B039376C1BB97CED6DE9A5691A1E0A66156709DC\
7DBDB2B05D5100920CA9760A6C2564ED6B0FD3902607D1D5D77423550EAE3E32F8B33F6DCDB48237AB6A03168459A775F7BFEDD50E8FF32E97B29C47\
AB96874597204608BA5C13F538F0900EAD2412D1CE105904CDB50306120C0706151269020E0202060802060E03061D030606151275010E060002124D\
0E0E0A0002151259010E0E1D03070002011C10126103000001042001020E0320000E072000151275010E0328000E0328001C0801000800000000001E\
01000100540216577261704E6F6E457863657074696F6E5468726F7773010801000200000000000D01000853514C5574696C73000005010000000017\
010012436F7079726967687420C2A920203230323200002901002436643732343736392D346666632D343966652D386561612D666136313330386138\
62313800000C010007312E302E302E3000004901001A2E4E45544672616D65776F726B2C56657273696F6E3D76342E380100540E144672616D65776F\
726B446973706C61794E616D65122E4E4554204672616D65776F726B20342E3880B3010002005455794D6963726F736F66742E53716C536572766572\
2E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572\
653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A4461746141636365737300000000540E11\
46696C6C526F774D6574686F644E616D650F46696C6C537472696E675461626C652401001F53514C5574696C732E53716C5574696C2B3C53706C6974\
7465723E645F5F310000040100000000B6ECAB35C4CC0AC896D3D3404EB66253CEF0E979635EF6ABBD1F00C96573B53D179A64C90C920112116D5900\
6D514E9A2B8F93C3866239B484803DC130276DAED8404492A11ACEB072A4DDF8C297A913673ED2417AE3FECFBFB5B2A7D0343A05EF2D3DEDFEC82553\
9BBA85A0C2AD2956F73B8DE88E4F5C558BB7065C9BCA81A50000000061F3D46300000000020000001C0100004C3300004C15000052534453849790AE\
7336D34085CC0E2F186C71EC01000000443A5C53514C53706C6974434C525C53514C5574696C735C6F626A5C52656C656173655C53514C5574696C73\
2E7064620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000903400000000000000000000AA3400000020000000000000\
000000000000000000000000000000009C340000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF25\
002000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000001001000000018000080000000000000000000000000\
000001000100000030000080000000000000000000000000000001000000000048000000584000001C03000000000000000000001C03340000005600\
53005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE00000100000001000000000000000100000000003F000000\
000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F000000000024000400\
00005400720061006E0073006C006100740069006F006E00000000000000B0047C020000010053007400720069006E006700460069006C0065004900\
6E0066006F0000005802000001003000300030003000300034006200300000001A000100010043006F006D006D0065006E0074007300000000000000\
22000100010043006F006D00700061006E0079004E0061006D00650000000000000000003A0009000100460069006C00650044006500730063007200\
69007000740069006F006E0000000000530051004C005500740069006C00730000000000300008000100460069006C00650056006500720073006900\
6F006E000000000031002E0030002E0030002E00300000003A000D00010049006E007400650072006E0061006C004E0061006D006500000053005100\
4C005500740069006C0073002E0064006C006C00000000004800120001004C006500670061006C0043006F0070007900720069006700680074000000\
43006F0070007900720069006700680074002000A90020002000320030003200320000002A00010001004C006500670061006C005400720061006400\
65006D00610072006B007300000000000000000042000D0001004F0072006900670069006E0061006C00460069006C0065006E0061006D0065000000\
530051004C005500740069006C0073002E0064006C006C0000000000320009000100500072006F0064007500630074004E0061006D00650000000000\
530051004C005500740069006C00730000000000340008000100500072006F006400750063007400560065007200730069006F006E00000031002E00\
30002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000031002E0030002E00\
30002E003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
00000000000000000000000000000000000000000000000000000000003000000C000000BC3400000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
WITH PERMISSION_SET = SAFE;
GO
CREATE FUNCTION ufn_SplitString
(
#s NVARCHAR(MAX),
#separators NVARCHAR(1000) = ''
)
RETURNS TABLE
(
s NVARCHAR(1000)
)
AS
EXTERNAL NAME SQLUtils.[SQLUtils.SqlUtil].SplitString;
GO
Finally you can test the added function:
SELECT s FROM dbo.ufn_SplitString('a|b|x','|');
SELECT s FROM dbo.ufn_SplitString('a,b,x',',');
SELECT s FROM dbo.ufn_SplitString('a,b|x','|,');
(I will continue on a new reply just to keep this thing not to long + splitting is itself a different part of the question)
I am wondering if I can retrieve the original SQL statement which fired of a particular SQL block.
Say I have a table with an AFTER INSERT, UPDATE trigger on it. From within the trigger, I would like to get the full text of the original INSERT or UPDATE statement that fired the trigger.
Is this possible? Mainly I want to be able to do this for logging/debugging purposes.
I haven't tried to do something like this in a trigger (nor would I necessarily) but you might try something like this.
select top 100
q.[text]
from sys.dm_exec_requests r
outer apply sys.dm_exec_sql_text(r.sql_handle) q
where r.session_id = ##spid
Great question! I use eventdata all the time with ddl triggers, but haven't thought about what to use for dml triggers. I think this is what you're looking for. It's definitely going into my toolbox!
Please note that the code below is for demonstration only. Returning output from a trigger is deprecated. In practice, you'd insert the output of the dbcc command into a log table.
if schema_id(N'log') is null execute (N'create schema log');
go
if object_id(N'[log].[data]'
, N'U') is not null
drop table [log].[data];
go
create table [log].[data] (
[id] [int] identity(1, 1)
, [flower] [sysname]);
go
if exists
(select *
from sys.triggers
where parent_class = 0
and name = 'get_log_dml')
drop trigger [get_log_dml] on database;
go
create trigger [get_log_dml] on [log].[data]
after insert, update
as
declare #dbcc table (
[event_type] [sysname]
, [parameters] [int]
, [event_info] [nvarchar](max)
);
select *
from inserted;
insert into #dbcc
([event_type],[parameters],[event_info])
execute (N'dbcc inputbuffer(##spid)');
select [event_type]
, [parameters]
, [event_info]
from #dbcc;
go
insert into [log].[data]
([flower])
values (N'rose');
Hi I have a database where we often need to delete records, however as this can sometimes be mistakenly done I was wondering is there a way to save a sort of history of SQL commands done, and the output to screen log of them? Thanks
Try this:
USE YourDatabase;
GO
CREATE TABLE ddl_log (PostTime datetime, DB_User nvarchar(100), Event nvarchar(100), TSQL nvarchar(2000));
GO
CREATE TRIGGER log
ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
DECLARE #data XML
SET #data = EVENTDATA()
INSERT ddl_log
(PostTime, DB_User, Event, TSQL)
VALUES
(GETDATE(),
CONVERT(nvarchar(100), CURRENT_USER),
#data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'),
#data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(2000)') ) ;
GO
--Test the trigger
CREATE TABLE TestTable (a int)
DROP TABLE TestTable ;
GO
SELECT * FROM ddl_log ;
GO
Reference
I see that you are using Sql Server.
You can write a trigger as someone suggest or you can configure Change Data Capture. CDC will have better performance.
We have a large Database (Many Table, SP, Function and...) and our database programers are over 10 person. All of theme can use the database on our main server computer or on his local system.
Our requirements:
we want each db programmer can apply his definitions (create table, triger, sp, fn &...) and modifications (on tables, sp, trigers, fn &...) by SQL SERVER MANAGMENT STUDIO (or your suggest tool) and get all of this activities as a TSQL Script at the end of each day.
So, we want a automatic log of our db programers activities as a TSQL script (sequence of sub tsql queries). for example:
My Activities:
My first activity>> I open my Customer table as design mode, by right
click on table and click Design. then i change datatype of ID field
from INT to BigInt. then save
My second activity>> I change
PR_Customer_Insert stored procedure and i execute it.
Now i want an executable log like this:
-- UserName: Ram
-- 2013-02-10 10:20:35
Alter Table ALTER TABLE Customer ALTER COLUMN Id TYPE bigint;
Go
-- UserName: Ram
-- 2013-02-10 10:45:00
Drop Sp DROP PROCEDURE dbo.PR_Customer_Insert;
-- UserName: Ram
-- 2013-02-10 10:45:00
Create sp CREATE PROCEDURE PR_Customer_Insert
#id int,
#name nvarchar(30) AS
INSERT INTO Customer
(
#id,
#name
)
GO
We know compare tow database is a solution but we want access to SSMS Query Pipeline...
My Questions:
Is there any way for this request (an automatically generated log that is an executable TSQL script)?
What is the best solutions for generate this scripts automatically???
What do you think about this idea in a team work on database?
Thanks...
Possible use DDL triggers, but on a certain database
Simple example:
--Create table EvtLog
CREATE TABLE EvtLog
(
LoginName NVARCHAR(100),
PostTime DATETIME,
EventType NVARCHAR(100),
TSQLCommand NVARCHAR(2000)
)
GO
--Create the DDL trigger
CREATE TRIGGER trPreventTblChange
ON DATABASE
FOR DROP_TABLE, CREATE_TABLE, ALTER_TABLE,
DROP_PROCEDURE, CREATE_PROCEDURE, ALTER_PROCEDURE
AS
DECLARE #Data XML
SET #Data = EventData()
INSERT EvtLog (LoginName, PostTime, EventType, TSQLCommand)
SELECT #Data.value('(/EVENT_INSTANCE/LoginName)[1]', 'nvarchar(100)'),
#Data.value('(/EVENT_INSTANCE/PostTime)[1]', 'nvarchar(100)'),
#Data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'),
#Data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(2000)');
GO
Set up a database DDL trigger and use the EVENTDATA Function to find out more information about what was done and insert that into a table that you can query at the end of the day
Example
CREATE TRIGGER [LogDDL] ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
DECLARE #xml XML;
SELECT #xml = EVENTDATA();
INSERT ChangeLog
(
ObjectName,
SQL
)
VALUES
(
#xml.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname'),
#xml.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)')
);
How can i know which sql statement fired through trigger for select, insert, update and delete on table?
As Jonas says, Profiler is your best option (and only option for SELECT queries). For INSERT, UPDATE, DELETEs, the closest you can get without Profiler may be to look at the input buffer via DBCC INPUTBUFFER(##SPID). This will only work for ad-hoc language events, not RPC calls, and will only show you the first 256 characters of the SQL statement (depending on version, I believe). Some example code, (run as dbo):
CREATE TABLE TBL (a int, b varchar(50))
go
INSERT INTO TBL SELECT 1,'hello'
INSERT INTO TBL SELECT 2,'goodbye'
go
GRANT SELECT, UPDATE ON TBL TO guest
go
CREATE TABLE AUDIT ( audittime datetime default(getdate())
, targettable sysname
, loginname sysname
, spid int
, sqltext nvarchar(max))
go
CREATE TRIGGER TR_TBL ON TBL FOR INSERT, UPDATE, DELETE
AS BEGIN
CREATE TABLE #DBCC (EventType varchar(50), Parameters varchar(50), EventInfo nvarchar(max))
INSERT INTO #DBCC
EXEC ('DBCC INPUTBUFFER(##SPID)')
INSERT INTO AUDIT (targettable, loginname, spid, sqltext)
SELECT targettable = 'TBL'
, suser = suser_name()
, spid = ##SPID
, sqltext = EventInfo
FROM #DBCC
END
GO
/* Test the Audit Trigger (can be run as guest) */
UPDATE TBL SET a = 3 WHERE a = 2
First, there are no select dml triggers, only triggers that work on INSERT, UPDATE or DELETE
Secondly, you can't know which sql statement triggered the trigger (at least not in the trigger). However, you can use profiler to debug what's happening in the database. There's a decent explanation of this here.