【问题标题】:Port STRING_AGG to FOR XML将 STRING_AGG 移植到 FOR XML
【发布时间】:2021-12-30 05:10:21
【问题描述】:

我目前正在处理Data Discovery and Classification,我有一个query,它允许我在进行分类时查看数据的预览。

这是一个如何与 AdventureWorks 对抗的示例:

DECLARE @TableName VARCHAR(100) = 'Product'

DROP TABLE IF EXISTS #ColumnsToDisplay

SELECT    ROW_NUMBER () OVER (ORDER BY tab.name) AS Iteration,
          SCHEMA_NAME (tab.schema_id) AS schema_name,
          tab.name AS table_name,
          --col.column_id,
          col.name AS column_name,
          --t.name AS data_type,
          --col.max_length,
          --col.precision,
          CAST(NULL AS VARCHAR(MAX)) AS DataSample
INTO      #ColumnsToDisplay
FROM      sys.tables AS tab
JOIN      sys.columns AS col
    ON    col.object_id = tab.object_id
--LEFT JOIN sys.types AS t
--    ON    col.user_type_id = t.user_type_id
WHERE     tab.name = @TableName

DECLARE @Iterations       INT = 0,
        @CurrentIteration INT = 1;

SELECT @Iterations = MAX (Iteration)
FROM   #ColumnsToDisplay 
WHILE @CurrentIteration <= @Iterations
BEGIN
    DECLARE @CurrentTableName  VARCHAR(100)   = '',
            @CurrentColumnName VARCHAR(100)   = '',
            @DynamicQuery      NVARCHAR(1000) = N''
    DECLARE @Sample VARCHAR(MAX)

    SET @CurrentTableName = '';
    SET @DynamicQuery = N'';

    SELECT @CurrentTableName = CONCAT (ttq.schema_name, '.', ttq.table_name),
           @CurrentColumnName = ttq.column_name
    FROM   #ColumnsToDisplay AS ttq
    WHERE  ttq.Iteration = @CurrentIteration

    IF (@CurrentTableName = '')
    BEGIN
        SET @CurrentIteration += 1

        CONTINUE
    END

    SET @DynamicQuery = CONCAT (N'
    SELECT @Sample = STRING_AGG(t.ColumnData,'', '') 
    FROM (
            SELECT TOP 5  CAST(x.', @CurrentColumnName, ' AS VARCHAR(MAX)) AS ColumnData 
            FROM ', @CurrentTableName, ' AS x 
            WHERE x.', @CurrentColumnName, ' IS NOT NULL
    )t')

    EXECUTE sys.sp_executesql @DynamicQuery,
                              N'@Sample VARCHAR(MAX) OUTPUT',
                              @Sample = @Sample OUTPUT

    UPDATE #ColumnsToDisplay
    SET    DataSample = @Sample
    WHERE  Iteration = @CurrentIteration

    SET @CurrentIteration += 1
END

SELECT ctd.Iteration,
       ctd.schema_name,
       ctd.table_name,
       --ctd.column_id,
       ctd.column_name,
       --ctd.data_type,
       --ctd.max_length,
       --ctd.precision,
       ctd.DataSample
FROM   #ColumnsToDisplay AS ctd

结果如下:

Iteration schema_name table_name column_name DataSample
1 Production Product ProductID 980, 365, 771, 404, 977
2 Production Product Name Adjustable Race, All-Purpose Bike Stand, AWC Logo Cap, BB Ball Bearing, Bearing Ball
3 Production Product ProductNumber AR-5381, BA-8327, BB-7421, BB-8107, BB-9108
4 Production Product MakeFlag 0, 0, 1, 0, 1
5 Production Product FinishedGoodsFlag 0, 0, 0, 0, 0
6 Production Product Color Black, Black, Black, Silver, Silver

问题在于该查询仅适用于 SQL Server 2017 及更高版本,因为它使用STRING_AGG。对于 SQL Server 2016 及更低版本,我应该改用 STUFF

我关注了这个example,但我无法真正修复它。

我唯一知道的是我需要移植的部分代码是这样的:

SET @DynamicQuery = CONCAT (N'
SELECT @Sample = STRING_AGG(t.ColumnData,'', '') 
FROM (
        SELECT TOP 5  CAST(x.', @CurrentColumnName, ' AS VARCHAR(MAX)) AS ColumnData 
        FROM ', @CurrentTableName, ' AS x 
        WHERE x.', @CurrentColumnName, ' IS NOT NULL
)t')

谁能帮我把STRING_AGG移植到STUFF

谢谢

【问题讨论】:

  • Stuff其实是不相关的,只是用来去掉多余的后缀分隔符,用for xml聚合字符串的例子不胜枚举。
  • 这能回答你的问题吗? String_agg for SQL Server before 2017
  • 有关使用 XML 进行聚合字符串连接的详细信息,请参阅 this answer
  • 旁白:您有注射风险。 CONCAT (ttq.schema_name, '.', ttq.table_name) 应该是 CONCAT (QUOTENAME(ttq.schema_name), '.', QUOTENAME(ttq.table_name))@CurrentColumnName 应该是 QUOTENAME(@CurrentColumnName)
  • 感谢@Charlieface,但此代码不会成为任何应用程序的一部分,我会亲手毁掉它

标签: sql-server tsql dynamic-sql for-xml-path string-agg


【解决方案1】:

首先,让我们澄清一下 stuff 就像 Stu 提到的那样,只是用来删除第一个分隔符。 所以,如果你有

'a','b','c' 

如果你想使用逗号分隔符,xml 路径会给你:

,a,b,c

然后你用东西把第一个逗号删掉:

a,b,c

您的查询似乎根本没有分隔符,因此您不会使用stuff。考虑到这一点,这是我未经测试的猜测,在它上面添加动态查询很棘手:

SET @DynamicQuery = CONCAT (N'
    set @Sample =
            ( 
                select t.ColumnData
                from ', @CurrentTableName, ' AS x 
                where x.', @CurrentColumnName, ' IS NOT NULL
                for xml path(''''), type
            ).value(''.'',''nvarchar(max)'')
)t')

【讨论】:

  • 奇怪,上面写着(1 row affected) Msg 102, Level 15, State 1, Line 9 Incorrect syntax near ')'.
  • print 可能吗?
【解决方案2】:

感谢您的帮助。

正确的问题是:

SET @DynamicQuery = CONCAT (N'
SELECT @Sample =  STUFF((SELECT '', ''+ t.ColumnData  
FROM (
        SELECT TOP 5 CAST(x.[', @CurrentColumnName, '] AS VARCHAR(MAX)) AS ColumnData 
        FROM ', @CurrentTableName, ' AS x 
        WHERE x.[', @CurrentColumnName, '] IS NOT NULL 
) AS t
   FOR XML PATH('''')),1,1,'''')')

【讨论】:

    猜你喜欢
    • 2011-08-12
    • 2020-04-06
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 2016-07-13
    • 2011-03-06
    • 2017-06-09
    • 2015-02-24
    相关资源
    最近更新 更多