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

时间:2015-06-02 17:43:53

标签: sql-server stored-procedures dynamic-sql sqlxml sql-function

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

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

我要做的是在我的主数据库中有一个存储过程,它将创建另一个包含所有相应函数/过程/等的数据库。所以在那个存储过程中,我试图做这样的事情:

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吗?如果没有,我怎样才能实现目标?谢谢。

1 个答案:

答案 0 :(得分:1)

问题不在于local-name功能。事实上,您将@cmd变量连接到动态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作为前缀,但没有其他字符串(我为其他字符添加了N,以便它们都具有该前缀)。