How to insert Error_Message using EXECUTE sp_executesql - sql

Using MS SQL Server I have the below code - it is being executed via a EXECUTE sp_executesql command:
Declare #Cmd nvarchar(max)
;with DistinctTables as
(
select distinct [DestTable], [SourceFile] from [tbl_IN_Ctrl_Dtl]
),
InsertCommands as
(
-- columns from Destination table
select *,
'BEGIN TRY insert into ' + [DestTable] + '(' +
STUFF((
SELECT ',' + [DestCol]
FROM [tbl_IN_Ctrl_Dtl] t1
where t1.DestTable = drt.DestTable
GROUP BY DestCol,ORDINAL_POSITION
ORDER BY ORDINAL_POSITION
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
+ ')' +
' select ' +
-- columns from source table
STUFF((
SELECT ',' + [SourceCol]
FROM [tbl_IN_Ctrl_Dtl] t1
where t1.DestTable = drt.DestTable
GROUP BY SourceCol,ORDINAL_POSITION
ORDER BY ORDINAL_POSITION
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
+ ' from ' + [SourceFile]
+ ';
update tbl_IN_Ctrl_Header set ErrMsg = ##ERROR where SourceFile_INSERT = 0 and SourceFile = ''' + [SourceFile]+ ''''
+';
update tbl_IN_Ctrl_Header set SourceFile_INSERT = 1 where SourceFile_INSERT = 0 and SourceFile = ''' + [SourceFile]+ ''''
+'; END TRY BEGIN CATCH'
as InsertCommand
from DistinctTables drt
)
select #cmd =
STUFF((
SELECT ';' + char(10) + [InsertCommand]
FROM InsertCommands
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
+';' from InsertCommands ic
--print #cmd
EXECUTE sp_executesql #cmd
I can retrieve the error number using line:
update tbl_IN_Ctrl_Header set ErrMsg = ##ERROR where SourceFile_INSERT = 0 and SourceFile = ''' + [SourceFile]+ ''''
However, how do I retrieve the actual text error message? If I use ERROR_MESSAGE I just get Null. How do I modify the above to update 'ErrMsg' to the actual text error message? I've put a BEGIN TRY at the beginning of the Insert and END TRY at the end of the UPDATE but I now receive the error Incorrect syntax near ';'.

Related

A SELECT INTO statement cannot contain a SELECT statement that assigns values to a variable

I am trying to create a stored procedure or function to find the number of null values in each column in a table.
I am having problems determining the syntax for converting the code to a stored procedure/function.
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = (
SELECT '
' +
STUFF((
SELECT ', [' + c.name + '] = ' + CASE WHEN c.is_nullable = 0 THEN '0' ELSE 'COUNT(*) - COUNT([' + c.name + '])' END
FROM sys.columns c
WHERE c.[object_id] = o.[object_id]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, 'SELECT ''' + SCHEMA_NAME(o.[schema_id]) + '.' + o.name + ''', COUNT(*), ') + '
FROM [' + SCHEMA_NAME(o.[schema_id]) + '].[' + o.name + ']'
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.is_ms_shipped = 0
AND [name] = 'BSEG'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
INTO xzy
PRINT #SQL
EXEC sys.sp_executesql #SQL
I want to stored the results in a table. But I am getting the following error message:
Msg 194, Level 15, State 1, Line 2
A SELECT INTO statement cannot contain a SELECT statement that assigns values to a variable.
So my ultimate aim is to have a stored procedure/function which upon execution will give number of null values in each column in a table and the results will be stored in another result table.
Can you please check with this following changes-
Remove assigning part from your query and just use the simple select statement as-
SELECT '' +
STUFF((
...
--Note: Write the SQL in such way so that only SQL
--text from STUFF functions is returned. There is no
--requirement of assigning the text first to variable #SQL
Add INSERT before INTO key as below-
...
INSERT INTO xzy
...
If still no luck, please provide output of PRINT #SQL command with above 2 changes.
The "INTO xyz" should go above "FROM sys.objects o"?
EDIT
Try this
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = (
SELECT '
' +
STUFF((
SELECT ', ' + CASE WHEN c.is_nullable = 0 THEN '0' ELSE 'COUNT(*) - COUNT([' + c.name + '])' END + ' AS [' + c.name + ']'
FROM sys.columns c
WHERE c.[object_id] = o.[object_id]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, 'SELECT ''' + SCHEMA_NAME(o.[schema_id]) + '.' + o.name + ''' as TableName, COUNT(*) as Cnt, ') + '
INTO xzy
FROM [' + SCHEMA_NAME(o.[schema_id]) + '].[' + o.name + ']'
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.is_ms_shipped = 0
AND [name] = 'BSEG'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
PRINT #SQL
EXEC sys.sp_executesql #SQL

Update (find and replace) in all column in SQL Server

I got this script for update data in table:
update [dbo].[temp_LABORATOR_copy]
set [PRA] = replace([PRA], '.', ',');
update [dbo].[temp_LABORATOR_copy]
set [PRV] = replace([PRV], '.', ',');
update [dbo].[temp_LABORATOR_copy]
set [TVK] = replace([TVK], '.', ',');
update [dbo].[temp_LABORATOR_copy]
set [eAl] = replace([eAl], '.', ',');
update [dbo].[temp_LABORATOR_copy]
set [efH] = replace([efH], '.', ',');
But there is 53 columns in the table and listing script for each column separately is inefficient. Is there a possibility to perform this script comprehensively for the whole table?
Like:
update [dbo].[temp_LABORATOR_copy]
set * = NULL
where * like '***'
To generate a script like that use dynamic sql.
DECLARE #tableName varchar(50) = '[dbo].[temp_LABORATOR_copy]'
DECLARE #sql VARCHAR(MAX)='';
-- columns
SELECT #sql = #sql
+ CASE len(#sql) WHEN 0 THEN '' ELSE ',' END
+ c.name + ' = CASE WHEN ' + c.name + ' LIKE ''***'' THEN NULL ELSE ' + c.name + ' END'
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(#tableName)
SET #sql = 'UPDATE ' + #tableName + ' SET ' +#sql ;
select #sql;
EXECUTE (#sql);
You can use dynamic SQL:
DECLARE #sql nvarchar(max)
SELECT #sql = (
SELECT 'update [dbo].[temp_LABORATOR_copy] set [' +COLUMN_NAME+'] = replace(['+COLUMN_NAME+'], ''.'', '','');'
FROM information_schema.columns
WHERE TABLE_NAME = 'temp_LABORATOR_copy'
AND COLUMN_NAME NOT IN ('Field2','Field3') -- Here put columns that must not be updated
AND DATA_TYPE IN ('nvarchar','varchar','nchar','char')
FOR XML PATH('')
)
--That will give you script like
--update [dbo].[temp_LABORATOR_copy] set [Field1] = replace([Field1], '.', ','); and etc
EXEC sp_executesql #sql

Moving table from one database to another with primary key and other keys

I want to move all the table from one database to another with primary key and all other keys
using SQL queries. I am using SQL Server 2005 and I got a SQL queries to move the table but the keys are not moved.
And my queries is as follows
set #cSQL='Select Name from SRCDB.sys.tables where Type=''U'''
Insert into #TempTable
exec (#cSQL)
while((select count(tName) from #t1Table)>0)
begin
select top 1 #cName=tName from #t1Table
set #cSQL='Select * into NEWDB.dbo.'+#cName+' from SRCDB.dbo.'+#cName +' where 1=2'
exec(#cSQL)
delete from #t1Table where tName=#cName
end
where SRCDB is the name of source database and NEWDB is the name of destination database
How can I achieve this..?
Can anyone help me in this...
Thank you...
The following T-SQL statement move all the table, primary key and foreign key from one database to another. Notice that the method SELECT * INTO FROM ... WHERE 1 = 2 does not create COMPUTED columns and user-data types. Suppose also that all primary keys are clustered
--ROLLBACK
SET XACT_ABORT ON
BEGIN TRAN
DECLARE #dsql nvarchar(max) = N''
SELECT #dsql += ' SELECT * INTO NEWDB.dbo.' + name + ' FROM SRCDB.dbo. ' + name + ' WHERE 1 = 2'
FROM sys.tables
--PRINT #dsql
EXEC sp_executesql #dsql
SET #dsql = N''
;WITH cte AS
(SELECT 1 AS orderForExec, table_name, column_name, constraint_name, ordinal_position,
'PRIMARY KEY' AS defConst, NULL AS refTable, NULL AS refCol
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
UNION ALL
SELECT 2, t3.table_name, t3.column_name, t1.constraint_name, t3.ordinal_position,
'FOREIGN KEY', t2.table_name, t2.column_name
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as t1
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE t2 ON t1 .UNIQUE_CONSTRAINT_NAME = t2.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE t3 ON t1.CONSTRAINT_NAME = t3.CONSTRAINT_NAME
AND t3.ordinal_position = t2.ordinal_position
)
SELECT #dsql += ' ALTER TABLE NEWDB.dbo.' + c1.table_name +
' ADD CONSTRAINT ' + c1.constraint_name + ' ' + c1.defConst + ' (' +
STUFF((SELECT ',' + c2.column_name
FROM cte c2
WHERE c2.constraint_name = c1.constraint_name
ORDER BY c2.ordinal_position ASC
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '') + ')' +
CASE WHEN defConst = 'FOREIGN KEY' THEN ' REFERENCES ' + c1.refTable + ' (' +
STUFF((SELECT ',' + c2.refCol
FROM cte c2
WHERE c2.constraint_name = c1.constraint_name
ORDER BY c2.ordinal_position ASC
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '') + ')' ELSE '' END
FROM (SELECT DISTINCT orderForExec, table_name, defConst, constraint_name, refTable FROM cte) AS c1
ORDER BY orderForExec
--PRINT #dsql
EXEC sp_executesql #dsql
COMMIT TRAN
You can generate customized script of Source Database and run the script for Destination Database.
Here is the link and slightly better [one][2]
Get the complete table and then perform the delete queries on Destination database as per requirement
If you want to do with Query. I guess this link would be helpful
DECLARE #strSQL NVARCHAR(MAX)
DECLARE #Name VARCHAR(50)
SELECT Name into #TempTable FROM SRCDB.sys.tables WHERE Type='U'
WHILE((SELECT COUNT(Name) FROM #TempTable) > 0)
BEGIN
SELECT TOP 1 #Name = Name FROM #TempTable
SET #strSQL = 'SELECT * INTO NEWDB.dbo.[' + #Name + '] FROM SRCDB.dbo.[' + #Name + ']'
EXEC(#strSQL)
DELETE FROM #TempTable WHERE Name = #Name
END
DROP TABLE #TempTable
If you have destination table already created then just set identity insert on and change query like below :
SET #strSQL = ' SET IDENTITY_INSERT NEWDB.dbo.[' + #Name + '] ON; ' +
' INSERT INTO NEWDB.dbo.[' + #Name + '] SELECT * FROM SRCDB.dbo.[' + #Name + ']' +
' SET IDENTITY_INSERT NEWDB.dbo.[' + #Name + '] OFF '
UPDATE :
If you don't want records and only want to create table with all key constaints then check this solution :
In SQL Server, how do I generate a CREATE TABLE statement for a given table?
The following script copies many tables from a source DB into another destination DB, taking into account that some of these tables have auto-increment columns:
http://sqlhint.com/sqlserver/copy-tables-auto-increment-into-separate-database

Generating Scripts for Specific Records in SQL Server

This is probably a bit of a limited, but valuable scenario. I have a SQL Server 2008 database with a table that has millions of records. There appears to be an intermittent problem with several of the records. I'm trying to repro the problem. In an effort to do this, I finally got the ID of an offending record. I would like to generate an INSERT statement associated with this single record in my PROD database. Then I can easily migrate it into my TESTING database in an effort to repro and resolve the problem.
Basically, I need to generate a single INSERT statement for a single record from a single table where I know the primary key value of the record.
Does anyone have any ideas of how I can accomplish this? Essentially, I want to generate insert statements on a conditional basis.
Thank you!
First try to recreate what you want to insert with a SELECT statement.
After that you can insert into the table with a INSERT INTO like this:
INSERT INTO tablename
SELECT ....
If they are on different servers, you can use INSERT like this:
INSERT INTO tablename VALUES (...)
using the values given by the SELECT in the other server fill the values in the insert.
In your specific case I think you can do this:
CREATE PROCEDURE dbo.GenerateSingleInsert
#table NVARCHAR(511), -- expects schema.table notation
#pk_column SYSNAME, -- column that is primary key
#pk_value INT -- change data type accordingly
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cols NVARCHAR(MAX), #vals NVARCHAR(MAX),
#valOut NVARCHAR(MAX), #valSQL NVARCHAR(MAX);
SELECT #cols = N'', #vals = N'';
SELECT #cols = #cols + ',' + QUOTENAME(name),
#vals = #vals + ' + ' + REPLICATE(CHAR(39),3) + ','
+ REPLICATE(CHAR(39),3) + ' + ' + REPLICATE(CHAR(39),2) + '+'
+ 'RTRIM(' + CASE WHEN system_type_id IN (40,41,42,43,58,61) THEN
'CONVERT(CHAR(8), ' + QUOTENAME(name) + ', 112) + '' ''
+ CONVERT(CHAR(14), ' + QUOTENAME(name) + ', 14)'
ELSE 'REPLACE(' + QUOTENAME(name) + ','''''''','''''''''''')' END + ')
+ ' + REPLICATE(CHAR(39),2)
FROM sys.columns WHERE [object_id] = OBJECT_ID(#table)
AND system_type_id <> 189 -- can't insert rowversion
AND is_computed = 0; -- can't insert computed columns
SELECT #cols = STUFF(#cols, 1, 1, ''),
#vals = REPLICATE(CHAR(39), 4) + ' + ' + STUFF(#vals, 1, 13, '')
+ REPLICATE(CHAR(39), 2);
SELECT #valSQL = N'SELECT #valOut = ' + #vals + ' FROM ' + #table + ' WHERE '
+ QUOTENAME(#pk_column) + ' = ''' + RTRIM(#pk_value) + ''';';
EXEC sp_executesql #valSQL, N'#valOut NVARCHAR(MAX) OUTPUT', #valOut OUTPUT;
SELECT SQL = 'INSERT ' + #table + '(' + #cols + ') SELECT ' + #valOut;
END
GO
So let's try it out:
CREATE TABLE dbo.splunge
(
ID INT, dt DATETIME, rv ROWVERSION, t NVARCHAR(MAX)
);
INSERT dbo.splunge(ID, dt, t)
SELECT 1, GETDATE(), 'foo'
UNION ALL SELECT 2, GETDATE(), 'bar'
UNION ALL SELECT 3, GETDATE(), 'O''Brien';
EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 1;
SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '1','20120517 10:07:07:330','foo'
EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 2;
SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '2','20120517 10:07:07:330','bar'
EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 3;
SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '3','20120517 10:07:07:330','O''Brien'
If there is an IDENTITY column you may need to set SET IDENTITY_INSERT ON for the TEST table, and verify that there is no collision. Probably about 500 caveats I should mention, I haven't tested all data types, etc.
However in the more general case there is a lot more to it than this. Vyas K has a pretty robust stored procedure that should demonstrate how complicated it can get:
http://vyaskn.tripod.com/code/generate_inserts_2005.txt
You are probably far better off using a tool like Red-Gate's SQL Data Compare to pick a specific row and generate an insert for you. As I've blogged about, paying for a tool is not just about the money, it's about the hours of troubleshooting and bug-fixing that someone else has already done for you.
Aaron,
I liked your code, it solved a problem for me. I ran into a few issues using it (like you said I would) with nulls and the text type so I made some changes to address those issues.
ALTER PROCEDURE dbo.GenerateSingleInsert
#table NVARCHAR(511), -- expects schema.table notation
#pk_column SYSNAME, -- column that is primary key
#pk_value INT -- change data type accordingly
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cols NVARCHAR(MAX), #vals NVARCHAR(MAX),
#valOut NVARCHAR(MAX), #valSQL NVARCHAR(MAX);
SELECT #cols = N'', #vals = N'';
SELECT #cols = #cols + ',' + QUOTENAME(name),
#vals = #vals + ' + '','' + ' + 'ISNULL('+REPLICATE(CHAR(39),4)+'+RTRIM(' +
CASE WHEN system_type_id IN (40,41,42,43,58,61) -- datetime types
THEN
'CONVERT(CHAR(8), ' + QUOTENAME(name) + ', 112) + '' ''+ CONVERT(CHAR(14), ' + QUOTENAME(name) + ', 14)'
WHEN system_type_id IN (35) -- text type NOTE: can overflow
THEN
'REPLACE(CAST(' + QUOTENAME(name) + 'as nvarchar(MAX)),'+REPLICATE(CHAR(39),4)+','+REPLICATE(CHAR(39),6)+')'
ELSE
'REPLACE(' + QUOTENAME(name) + ','+REPLICATE(CHAR(39),4)+','+REPLICATE(CHAR(39),6)+')'
END
+ ')+' + REPLICATE(CHAR(39),4) + ',''null'') + '
FROM sys.columns WHERE [object_id] = OBJECT_ID(#table)
AND system_type_id <> 189 -- can't insert rowversion
AND is_computed = 0; -- can't insert computed columns
SELECT #cols = STUFF(#cols, 1, 1, ''),
#vals = REPLICATE(CHAR(39),2) + STUFF(#vals, 1, 6, '') + REPLICATE(CHAR(39),2) ;
SELECT #valSQL = N'SELECT #valOut = ' + #vals + ' FROM ' + #table + ' WHERE '
+ QUOTENAME(#pk_column) + ' = ''' + RTRIM(#pk_value) + ''';';
EXEC sp_executesql #valSQL, N'#valOut NVARCHAR(MAX) OUTPUT', #valOut OUTPUT;
SELECT SQL = 'INSERT ' + #table + '(' + #cols + ') SELECT ' + #valOut;
END

xquery loop over columns

I have been tasked with creating a service broker using Xquery to handle tracking changes on a collection of tables. I have figured out how to pass the messages (xml of column names and the updated and deleted tables for the statements). The aim is to get the list of column names and then compare the like column for each updated/deleted row and not a change.
Here is a sample of the XML:
<Update xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<TableName>
<ID>2414</ID>
<fkEvent>2664</fkEvent>
<fkType xsi:nil="true" />
<Description>Phil Test 3</Description>
<DTS>2011-04-04T14:01:36.533</DTS>
<uID>192204FA-612F-46F4-A6CB-1B4D53769A81</uID>
<VersionID xsi:nil="true" />
<UpdateDateTime>2011-04-04T14:04:31.013</UpdateDateTime>
<DeleteFlag>0</DeleteFlag>
<Updated>0</Updated>
<Owner>42</Owner>
<CreatedBy>42</CreatedBy>
</TableName>
</Update>
Generated by:
SET #xml1 = (SELECT * FROM TableName ORDER BY ID DESC FOR XML AUTO, ELEMENTS XSINIL, ROOT('MsgEnv'))
I have the following code:
WHILE #cnt <= #totCnt BEGIN
SELECT #child = #ColNames.query('/Columns/name[position()=sql:variable("#cnt")]')
SET #CurrentCol = REPLACE(REPLACE(CAST(#child AS VARCHAR(500)), '<name>', ''), '</name>', '')
PRINT #CurrentCol
WHILE #updateCnt <= #updateCntTotal BEGIN
SELECT #childUpdate = #xml1.query('/Update/TableName/sql:variable("#CurrentCol")')
PRINT CAST(#childUpdate AS VARCHAR(MAX))
WHILE #deleteCnt <= #deleteCntTotal BEGIN
SELECT #deleteCnt = #deleteCnt + 1
END
SET #deleteCnt = 1
SELECT #updateCnt = #updateCnt + 1
END
SET #updateCnt = 1
SELECT #cnt = #cnt + 1
END
The trouble I am having is dynamically setting the column name for this statement:
SELECT #childUpdate = #xml1.query('/Update/TableName/sql:variable("#CurrentCol")')
I have tried a few different variations using the sql:variable. Is it not possible to do this? I'd like to be able to do this dynamically as there are lots of tables we need to "audit" changes on.
Edit 1:
SELECT #childUpdate = #xml1.query('/Update/TableName/*[name() = sql:variable("#CurrentCol")]')
Yields this error (including the . in the () has a similar effect.
Msg 2395, Level 16, State 1, Line 34
XQuery [query()]: There is no function '{http://www.w3.org/2004/07/xpath-functions}:name()'
Your XQuery expression:
/Update/TableName/sql:variable("#CurrentCol")
It will call sql:variable() extension function for each /Update/TableName element.
If you want to select TableName's child with the same name as the string result of your extension function, then use:
/Update/TableName/*[name(.) = sql:variable("#CurrentCol")]
The previous answer didn't help at all but here is what I have found to work for this situation. The trigger will pass in 4 XML strings. The first contains the column information, the next two are the XML contents of the INSERTED and DELETED temporary tables, and the last is a Meta string (schema name, table name, updated by user, timestamp, etc).
Here is what the column XML code looks like:
DECLARE #ColNames XML
DECLARE #ColumnTypeInfo TABLE (
column_name varchar(100),
data_type varchar(100))
INSERT INTO #ColumnTypeInfo (column_name,data_type)
(
SELECT column_name 'column_name',
CASE WHEN
DATA_TYPE = 'datetime' OR DATA_TYPE = 'int' OR DATA_TYPE = 'bit' OR
DATA_TYPE = 'uniqueidentifier' OR DATA_TYPE = 'sql_variant'
THEN DATA_TYPE ELSE
CASE WHEN CHARACTER_MAXIMUM_LENGTH IS NOT NULL THEN
data_type + '(' +
CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR(10))
+ ')'
ELSE
CASE WHEN NUMERIC_PRECISION IS NOT NULL AND NUMERIC_SCALE IS NOT NULL THEN
data_type + '(' +
CAST(NUMERIC_PRECISION AS VARCHAR(10))
+ ',' +
CAST(NUMERIC_SCALE AS VARCHAR(10))
+ ')'
ELSE
DATA_TYPE
END
END
END 'data_type'
FROM information_schema.columns WHERE table_name = 'tbl_ActivityPart'
)
SET #ColNames = (
SELECT * FROM #ColumnTypeInfo
FOR XML PATH ('Column'), ROOT('ColumnDef')
)
#ColNames is passed into the message queue.
This is the basis for the procedure that processes the queued messages:
WHILE #cnt <= #totCnt BEGIN
SET #CurrentCol = CAST(#ColNames.query('for $b in /ColumnDef/Column[position()=sql:variable("#cnt")]/column_name return ($b)') AS VARCHAR(MAX))
SET #CurrentCol = REPLACE(REPLACE(#CurrentCol, '<column_name>', ''), '</column_name>', '')
SET #DataType = CAST(#ColNames.query('for $b in /ColumnDef/Column[position()=sql:variable("#cnt")]/data_type return ($b)') AS VARCHAR(MAX))
SET #DataType = REPLACE(REPLACE(#DataType, '<data_type>', ''), '</data_type>', '')
SET #updateQuery = '/Update/Scheme.TableName/'+#CurrentCol
SET #SQL = 'SELECT #TmpXML = #UpdatedXML.query(''' + #updateQuery + ''')'
EXEC sp_executesql #SQL, N'#UpdatedXML xml, #TmpXML XML output', #UpdatedXML, #TmpXML output
SET #childUpdate = #TmpXML
SET #NewValue = REPLACE(REPLACE(CAST(#childUpdate AS VARCHAR(8000)), '<'+#CurrentCol+'>', ''), '</'+#CurrentCol+'>', '')
IF (CHARINDEX('xsi:nil="true"', CONVERT(VARCHAR(8000), #NewValue)) <> 0) BEGIN
SET #NewValue = NULL
END
SET #deleteQuery = '/Delete/Scheme.TableName/'+#CurrentCol
SET #SQL = 'SELECT #TmpXML = #DeletedXML.query(''' + #deleteQuery + ''')'
EXEC sp_executesql #SQL, N'#DeletedXML xml, #TmpXML XML output', #DeletedXML, #TmpXML output
SET #childDelete = #TmpXML
SET #OldValue = REPLACE(REPLACE(CAST(#childDelete AS VARCHAR(8000)), '<'+#CurrentCol+'>', ''), '</'+#CurrentCol+'>', '')
IF (CHARINDEX('xsi:nil="true"', CONVERT(VARCHAR(8000), #OldValue)) <> 0) BEGIN
SET #OldValue = NULL
END
IF #NewValue <> #OldValue BEGIN
INSERT INTO #Changes (SchemaName, TableName, FieldName, DTS,
[uID], OldValue, NewValue, ValueDataType, [User])
SELECT #Schema, #TableName, #CurrentCol, #TimeStamp,
CONVERT(UNIQUEIDENTIFIER, #CurrentUID), #OldValue, #NewValue, #DataType, #UpdateUserID
END
-- **********************************************************************************************************
SELECT #cnt = #cnt + 1
END
The contents of #Changes is then inserted into the permanent table (which is now on a separate disk volume from the rest of the tables in that database).