如何在动态 sql 语句中使用 local-name(.)

How to use local-name(.) within dynamic sql statement

我有以下代码来创建 SQL 函数,该函数将解析 XML 字符串并创建 table 表示节点和值的键值对。这在我的用例中对我来说很好用。

CREATE FUNCTION XmlToKeyValue
(   
    @rootName AS varchar(256),
    @xml AS Xml
)
RETURNS @keyval TABLE ([key] varchar(max), [value] varchar(max))
AS
BEGIN
    DECLARE @input TABLE (XmlData XML NOT NULL)
    INSERT INTO @input VALUES(@xml)

    INSERT @keyval ([key], [value])
    SELECT
        XC.value('local-name(.)', 'varchar(max)') AS [key],
        XC.value('(.)[1]', 'varchar(max)') AS [value]
    FROM
        @input
    CROSS APPLY
        XmlData.nodes('/*[local-name()=sql:variable("@rootName")]/*') AS XT(XC)

    RETURN
END

我想做的是在我的主数据库中有一个存储过程,它将创建另一个具有所有适当 functions/procedures/etc 的数据库。所以在那个存储过程中我试图做这样的事情:

SET @cmd = '
CREATE FUNCTION XmlToKeyValue
(   
    @rootName AS varchar(256),
    @xml AS Xml
)
RETURNS @keyval TABLE ([key] varchar(max), [value] varchar(max))
AS
BEGIN
    DECLARE @input TABLE (XmlData XML NOT NULL)
    INSERT INTO @input VALUES(@xml)

    INSERT @keyval ([key], [value])
    SELECT
        XC.value(''local-name(.)'', ''varchar(max)'') AS [key],
        XC.value(''(.)[1]'', ''varchar(max)'') AS [value]
    FROM
        @input
    CROSS APPLY
        XmlData.nodes(''/*[local-name()=sql:variable("@rootName")]/*'') AS XT(XC)

    RETURN
END
'
BEGIN TRY
    EXEC(N'USE '+@dbName+'; EXEC sp_executesql N''' + @cmd + '''; USE master')
END TRY
BEGIN CATCH
    PRINT 'Error creating XmlToKeyValue'
    Print Error_Message();
    RETURN
END CATCH

但是,我收到以下错误,我不知道如何解决。

Error creating XmlToKeyValue
Incorrect syntax near 'local'.

我可以在动态 sql 语句中使用 local-name 吗?如果没有,我怎样才能实现我的目标?谢谢。

问题不在于 local-name 函数。这完全是您将 @cmd 变量连接到 Dynamic SQL 中而没有正确转义嵌入的单引号的事实。

这一行:

EXEC(N'USE '+@dbName+'; EXEC sp_executesql N''' + @cmd + '''; USE master')

应该是:

SET @cmd = REPLACE(@cmd, N'''', N'''''');
EXEC(N'USE ' + @dbName + N'; EXEC sp_executesql N''' + @cmd + N''';');

否则你要嵌入:

XC.value(''local-name(

进入字符串,但使用相同数量的转义序列,因此 XC.value( 现在成为字符串的结尾,并且 local-name(.) 在技术上是未转义的 SQL 而不是部分一个字符串。

还有:

  1. 动态 SQL 末尾不需要 USE master(所以我删除了它)。
  2. 您在第一个字符串文字前添加了 N 前缀,但在其他字符串文字中添加了 none(我为其他字符串添加了 N,以便它们都具有该前缀)。