【问题标题】:How to simulate STRING_AGG (contrary of split) function如何模拟 STRING_AGG(拆分相反)函数
【发布时间】:2021-06-15 23:47:17
【问题描述】:

如何模拟string_agg函数?

我需要这个

[value]
1
2
3

进入这个

1,2,3

我试过了

CREATE TYPE stringArray AS TABLE ([value] nvarchar(255))
GO

CREATE FUNCTION dbo.ufn_join 
(
    @table stringArray readonly, 
    @separator nvarchar(5) = ','
)
    RETURNS nvarchar(max)
AS
BEGIN
    RETURN stuff((select @separator + value from @table for xml path('')), 1, 1, '')
END
GO

SELECT dbo.ufn_join(
    (
    SELECT cast(1 as nvarchar(255)) as value
    UNION
    SELECT cast(2 as nvarchar(255)) as value
    UNION
    SELECT cast(3 as nvarchar(255)) as value
    )
    , DEFAULT
)

但我遇到了一个错误

-- Error: Operand type clash: nvarchar is incompatible with stringArray

唯一的条件是我不想使用任何类型的变量。 CLR 函数也完全没问题,但我也有同样的问题,如何将 select 的返回值作为参数插入到函数中

【问题讨论】:

  • 您无法通过内联 TVP。 DECLARE @t stringArray; INSERT @t VALUES ...。如果您不喜欢这种语法,那么这种方法简直就是死路一条。 T-SQL 不相信语法糖。
  • 有很多重复的问题,最终指向the same article by Aaron Bertrand。那里正确描述了 XML 选项。但是,您不能 将其转换为函数,或者将某些表名传递给它。 SQLCLR 是最快的选择
  • @TheGameiswar 我同意解决方案是相同的,但问题是不同的(有点)。 STRING_AGG 是 SQL Server 2017 函数,GROUP_CONCAT 是 MYSQL。很少有人在 google 搜索 STRING_AGG 的替代品会发现和/或从您发布的文章中受益。那是我的 0.02 美元

标签: sql-server sql-server-2008 tsql


【解决方案1】:

当我想连接行时,通常我会使用此链接。有几种方法可以做到这一点,所以在这里你可以找到你最喜欢哪种方法的灵感。请注意 XML PATH,因为它使用您所有的 CPU 进程,并且可以将您的 CPU 最大化到 100%。

Different concat approaches

链接示例:

CREATE FUNCTION dbo.udf_select_concat ( @c INT )
RETURNS VARCHAR(MAX) AS BEGIN
DECLARE @p VARCHAR(MAX) ;
       SET @p = '' ;
    SELECT @p = @p + ProductName + ','
      FROM Northwind..Products
     WHERE CategoryId = @c ;
RETURN @p
END


SELECT CategoryId, dbo.udf_select_concat( CategoryId )
FROM Northwind..Products
GROUP BY CategoryId ;

【讨论】:

  • 相反,XML PATH 是 SQLCLR 之后最快的方法。您在此处发布的是奇特的更新,它需要 两倍 的时间是 XML。它不是uses all of your CPU Processes - 没有这样的事情。它并行执行。它确实在单个线程上运行,就像古怪的更新一样。不过速度是原来的两倍,这意味着奇怪的更新实际上需要更多的 CPU 时间来完成
  • 不是“古怪的更新”......古怪的更新完全是另外一回事。而且,不,XML 并不比真正的古怪更新快。在适当的设置中,没有什么比古怪的更新更快的了。古怪更新的唯一问题是它们依赖于未记录的行为(依赖于没有 ORDER BY 子句的聚集索引的顺序),这意味着不能保证它会产生正确的结果。
  • 带有 varchar(max) 的标量 udf 会很慢,并且永远不会享受并行执行计划。这种方法也有其他缺点;请注意这篇文章中 Martin Smith 的 cmets:stackoverflow.com/questions/15138593/…。 XML 方法是一种 hack,但它很有效。此外,关于“XML 路径是最快的”——有两种 XML 路径方法:一种可以防止保留的 XML 字符(包括 PATH 和 VALUE),另一种是 OP 发布的没有。前者的速度是后者的 1/2。
  • @PanagiotisKanavos 我的例子不是它更快,而是从链接中粘贴一些东西。此外,我可以向您保证,XML PATH 可以使 CPU 达到 100% 的最大值。我自己在更大的数据集上对此进行了测试。然而,提到这一点,我自己也倾向于在较小的数据集上使用 XML PATH。
  • @plaidDK 我什至不必保证XML PATH can make the CPU to max out to 100% 是错误的,因为它没有意义 - 运算符不是多线程的。基准测试来自最好的 SQL Server MVP 和作者之一。可能是您链接到的文章作者的老师。这意味着,您用来衡量绩效的非正式方式存在问题。至于was not that it was faster,考虑一下。单核操作总是会使用整个 CPU CORE 直到它完成。更慢确实意味着更多的 CPU
【解决方案2】:

抛开 TVP 问题不谈,通过将函数转换为内联表值函数(通常称为 内联 标量函数 (iSF)),您的函数将变得更快、更高效。这篇文章详细解释了我所说的: How to Make Scalar UDFs Run Faster (SQL Spackle)

CREATE FUNCTION dbo.ufn_join (@separator nvarchar(5))
RETURNS TABLE WITH SCHEMABINDING AS RETURN
SELECT concatinatedTxt = 
  stuff((select @separator + someTxt from dbo.someTable for xml path('')), 1, 1, '');

【讨论】:

    【解决方案3】:

    这是因为你声明了一个类型,将该类型设置为一个参数,并试图在这个参数中插入一个表(不同的类型)。

    试试这个:

    CREATE TYPE stringArray AS TABLE ([value] nvarchar(255))
    GO
    
    CREATE FUNCTION dbo.ufn_join 
    (
        @table stringArray readonly, 
        @separator nvarchar(5) = ','
    )
        RETURNS nvarchar(max)
    AS
    BEGIN
        RETURN stuff((select @separator + value from @table for xml path('')), 1, 1, '')
    END
    GO
    
    DECLARE @table stringArray
    
    INSERT INTO @Table
    SELECT cast(1 as nvarchar(255)) as value
    UNION
    SELECT cast(2 as nvarchar(255)) as value
    UNION
    SELECT cast(3 as nvarchar(255)) as value
    
    SELECT dbo.ufn_join(
        @Table
        , DEFAULT
    )
    

    【讨论】:

      猜你喜欢
      • 2017-08-01
      • 1970-01-01
      • 2020-03-20
      • 1970-01-01
      • 1970-01-01
      • 2018-12-22
      • 2022-08-17
      • 1970-01-01
      • 2018-08-05
      相关资源
      最近更新 更多