在需要字符串文字的地方使用SQL参数

在需要字符串文字的地方使用SQL参数,sql,sql-server,xml,tsql,delimited-text,Sql,Sql Server,Xml,Tsql,Delimited Text,我试图将顶级解决方案的最顶级代码从转换为SQL用户定义函数。但是,当我尝试在value函数的第一个参数中使用一个变量作为数字4时,它会呕吐 所以这是可行的: SELECT CAST('<x>' + REPLACE(@Input,',','</x><x>') + '</x>' AS XML).value('/x[4]','int') …但每当我尝试替换'/x[4]'以使用变量代替4时,我会收到如下消息 XML数据类型方法值的参数1必须是字符串文字

我试图将顶级解决方案的最顶级代码从转换为SQL用户定义函数。但是,当我尝试在value函数的第一个参数中使用一个变量作为数字4时,它会呕吐

所以这是可行的:

SELECT CAST('<x>' + REPLACE(@Input,',','</x><x>') + '</x>' AS XML).value('/x[4]','int')
…但每当我尝试替换'/x[4]'以使用变量代替4时,我会收到如下消息

XML数据类型方法值的参数1必须是字符串文字

这是我目前为止完整的用户定义函数。。。只是学习如何:

USE [DBName]
GO

CREATE FUNCTION fx_SegmentN
    (@Input AS VARCHAR(100),
     @Number AS VARCHAR(1)) 
RETURNS varchar(100)
AS
BEGIN
    DECLARE @ValueStringLiteral varchar(14)
    SET @ValueStringLiteral = '/x[' + @Number + ']'

    RETURN '' + 
        CASE
            WHEN @Number <1
                THEN ('ERROR')
            WHEN @Number = 1
                THEN (LEFT(@Input, CHARINDEX('-', @Input, 1)-1))
            WHEN @Number > 1
                --THEN (SELECT CAST('<x>' + REPLACE(@Input,',','</x><x>') + '</x>' AS XML).value('/x[4]','int')) --THIS LINE WORKS
                THEN (SELECT CAST('<x>' + REPLACE(@Input,',','</x><x>') + '</x>' AS XML).value('/x[' + @Number + ']','int')) --THIS ONE DOES NOT
            ELSE
                (NULL)
        END + ''
END

这是一个丑陋的黑客,但它的工作:

DECLARE @Query AS NVARCHAR(MAX) = N'SELECT CAST(''<x>'' + REPLACE(''' + @Input + ''' ,'','',''</x><x>'') + ''</x>'' AS XML).value(''/x['+ @Number + ']'',''int'')'
EXEC sp_executesql @Query
试试这个:

CREATE FUNCTION fx_SegmentN
    (
         @Input AS VARCHAR(100)
        ,@Number AS VARCHAR(1)
    ) RETURNS varchar(100)
    AS
BEGIN
    DECLARE @XML XML;
    DECLARE @value VARCHAR(100);

    SET @XML = CAST('<x>' + REPLACE(@Input,',','</x><x>') + '</x>' AS XML);

    WITH DataSource ([rowID], [rowValue]) AS
    (
        SELECT ROW_NUMBER() OVER (ORDER BY T.c ASC) 
              ,T.c.value('.', 'VARCHAR(100)')
        FROM @XML.nodes('./x') T(c)
    )
    SELECT @value = [rowValue]
    FROM DataSource
    WHERE [rowID] = @Number;

    RETURN @value;
END

GO

SELECT dbo.fx_SegmentN ('1a,2b,3c,4d,5e,6f,7g,8h', 3);

你可能会对

感兴趣,其实很简单:

declare @x xml = N'
  <x>2345</x>
  <x>vsaaef</x>
  <x>fxcfs</x>
  <x>Number 4</x>
  <x>vxcv</x>
  <x>111</x>
';
declare @Position int = 4;

select t.c.value('./text()[1]', 'nvarchar(100)')
from @x.nodes('/x[position() = sql:variable("@Position")]') t(c);

为什么要将数字作为字符串传递?您在问题中找到并链接的答案为您提供了解决方案:当然,您可以使用变量作为分隔符和位置使用sql:列直接从查询的值检索位置:DECLARE@dlmt NVARCHAR10=N';声明@pos INT=2;选择CASTN+REPLACE@input,@dlmt,N+N作为XML.value'/x[sql:variable@pos][1] ’,'nvarcharmax'可能的复制品是非常昂贵的,首先创建一组所有可能的元素,只是为了扔掉它并返回我们需要的一个。。。此外,您的函数在@input中使用了禁用字符。多行标量函数是性能杀手。。。此外,它是没有文件记录的,因此不保证,这个行数黑客将在任何情况下工作,并将继续在未来的版本工作。真的不是最好的解决办法。清楚地显示了如何为此使用sql:variable或sql:column。@Shnugo肯定-标量函数不好,在sql Server 2019之前没有并行性。无论如何,输入的最大长度为100,更具体地说,如果我们进行这些操作的性能测试,我们可能最终只会对数据进行标准化。是的,@Shnugo,真是太遗憾了:希望如此-@Shnugo,你的评论说服我使用比我尝试的方法更有效的方法。因此,我使用了下面列出的选项,当然您可以使用变量作为分隔符和位置使用sql:column直接从查询的值检索位置,同时我希望原始答案首先清楚地表明您的偏好,谢谢!这将与@input中的禁用字符中断,甚至不需要。中清楚地显示了如何使用sql:variable或sql:column解决此问题。这在原则上是正确的,但代价不必要。这提供了一个更好的方法。对于您的案例,这是选择@x.value'/x[sql:variable@Position]/文本[1],“nvarchar100”。@Shnugo,可能吧,尽管我还没有比较执行计划。但是如果答案已经知道了,那么问这个问题有什么意义呢?我遗漏了一些细节吗?将它标记为复制品,然后就可以使用它了。无意冒犯。。。链接问题中公认的答案并不是最佳答案。这就是为什么我没有将其链接为副本。。。OP没有在那里找到现有的解决方案。。。