我的任务是使用Xquery创建一个服务代理来处理对一组表的跟踪更改。我已经想出了如何传递消息(列名的xml以及语句的更新和删除的表)。目的是获取列名列表,然后比较每个更新/删除行的类似列,而不是更改。
以下是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>
生成者:
SET @xml1 = (SELECT * FROM TableName ORDER BY ID DESC FOR XML AUTO, ELEMENTS XSINIL, ROOT('MsgEnv'))
我有以下代码:
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
我遇到的麻烦是动态设置此语句的列名:
SELECT @childUpdate = @xml1.query('/Update/TableName/sql:variable("@CurrentCol")')
我使用sql:变量尝试了一些不同的变体。是不是可以这样做?我希望能够动态地执行此操作,因为有很多表需要“审核”更改。
编辑1:
SELECT @childUpdate = @xml1.query('/Update/TableName/*[name() = sql:variable("@CurrentCol")]')
产生此错误(包括()中的。具有类似的效果。
Msg 2395, Level 16, State 1, Line 34
XQuery [query()]: There is no function '{http://www.w3.org/2004/07/xpath-functions}:name()'
答案 0 :(得分:0)
您的XQuery表达式:
/Update/TableName/sql:variable("@CurrentCol")
它将为每个sql:variable()
元素调用/Update/TableName
扩展函数。
如果您想选择TableName
的孩子,其名称与您的分机功能的字符串结果相同,请使用:
/Update/TableName/*[name(.) = sql:variable("@CurrentCol")]
答案 1 :(得分:0)
之前的回答根本没有帮助,但这是我发现为这种情况工作的。触发器将传入4个XML字符串。第一个包含列信息,接下来的两个是INSERTED和DELETED临时表的XML内容,最后一个是元字符串(模式名称,表名,用户更新,时间戳等)。
以下是列XML代码的样子:
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被传递到消息队列中。
这是处理排队消息的过程的基础:
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
然后将@Changes的内容插入到永久表中(该表现在位于与该数据库中其余表的单独磁盘卷上)。