【问题标题】:How to coalesce into multiple columns with grouping?如何通过分组合并成多个列?
【发布时间】:2017-07-27 06:29:31
【问题描述】:

如果您运行以下代码,您将获得如下所示的结果:

ITEM    DIFF_QTY        DATE_OUTGO                              WAREH  COMPANY
1000    -5, -3, -4,     2017-08-01, 2017-08-02, 2017-08-03,     WH     CMP

太棒了,这就是我正在寻找的输出。遗憾的是,这仅在选择特定 ITEM 时有效。如果我删除 WHERE 则所有内容都放在同一行输出中。

那么我如何通过分组 (ITEM, WAREH, COMPANY) 来分离结果?所以最终的结果应该是这样的:

ITEM    DIFF_QTY        DATE_OUTGO                              WAREH  COMPANY
1000    -5, -3, -4,     2017-08-01, 2017-08-02, 2017-08-03,     WH     CMP
1001    -10, -13        2017-08-01, 2017-08-03                  WH     CMP

代码

DECLARE @tempTable TABLE (
    ITEM nvarchar(32),
    DIFF_QTY nvarchar(6), 
    DATE_OUTGO nvarchar(10),
    WAREH nvarchar(5),
    COMPANY nvarchar(5)
)

INSERT INTO @tempTable (ITEM, DIFF_QTY, DATE_OUTGO, WAREH, COMPANY)
VALUES 
(1000, '-5', '2017-08-01', 'WH', 'CMP'),
(1000, '-3', '2017-08-02', 'WH', 'CMP'),
(1000, '-4', '2017-08-03', 'WH', 'CMP'),
(1001, '-10', '2017-08-01', 'WH', 'CMP'),
(1001, '-13', '2017-08-03', 'WH', 'CMP')

SELECT * 
FROM @tempTable

DECLARE @itemNum nvarchar(32)
DECLARE @diffQty nvarchar(max)
DECLARE @dateOutgo nvarchar(max)
DECLARE @warehouse nvarchar(5)
DECLARE @company nvarchar(5)

SET @diffQty = ''
SET @dateOutgo = ''

SELECT 
    @itemNum = ITEM, 
    @diffQty = @diffQTY + DIFF_QTY + ', ',
    @dateOutgo = @dateOutgo + DATE_OUTGO + ', ', 
    @warehouse = WAREH, 
    @company = COMPANY 
FROM 
    @tempTable
WHERE 
    ITEM = 1000

SELECT @itemNum ITEM_NUM, @diffQty DIFF_QTY, @dateOutgo DATE_OUTGO, @warehouse WAREHOUSE, @company COMPANY

我查看了有关合并的多个线程,但几乎每个解决方案都要求您不要同时执行多项操作(SELECT、GROUP、COALESCE、多列等...)

【问题讨论】:

  • 在 SQL Server 中搜索 STRING_AGG。 SQL Server 2017 中的 XML/CLR 函数/STRING_AGG 有很多方法。ListAGG in SQLSERVER 同样使用 @var = @var + ... 可能是未定义的。
  • 我会查一下(之前看过),2016 版可以用吗?
  • 这里有使用SQL Server 2017 String_AGG的解决方案。
  • @lad2025 看起来真的很优雅!
  • @lad2025 遗憾的是我不能使用它。 “STRING_AGG”不是可识别的内置函数名称。

标签: sql-server tsql sql-server-2016


【解决方案1】:

您不能使用标量变量,例如@itemNum nvarchar(32),来存储表格数据。

您想要实现的输出通常在 SQL Server 中使用FOR XML PATH 生成:

SELECT t.ITEM,
       STUFF((SELECT  ',' + x.DIFF_QTY
              FROM @tempTable AS x
              WHERE x.ITEM = t.ITEM AND 
                    x.WAREH = t.WAREH AND
                    x.COMPANY = t.COMPANY
              FOR XML PATH('')), 1, 1, '') AS DIFF_QTY,
       STUFF((SELECT  ',' + x.DATE_OUTGO
              FROM @tempTable AS x
              WHERE x.ITEM = t.ITEM AND 
                    x.WAREH = t.WAREH AND
                    x.COMPANY = t.COMPANY
              FOR XML PATH('')), 1, 1, '') AS DATE_OUTGO
FROM @tempTable AS t
GROUP BY t.ITEM, t.WAREH, t.COMPANY

输出:

ITEM    DIFF_QTY    DATE_OUTGO
-----------------------------------------------------
1000    -5,-3,-4    2017-08-01,2017-08-02,2017-08-03
1001    -10,-13     2017-08-01,2017-08-03

【讨论】:

  • 这是最快的答案(比 Felix 快一点)。
【解决方案2】:

您可以使用FOR XML PATH('') 连接值:

SELECT
    t1.ITEM,
    a.DIFF_QTY,
    b.DATE_OUTGO,
    t1.WAREH,
    t1.COMPANY
FROM @tempTable t1
CROSS APPLY(
    SELECT DIFF_QTY =  STUFF((
        SELECT ', ' + CAST(t2.DIFF_QTY AS VARCHAR(100))
        FROM @tempTable t2
        WHERE
            t2.ITEM = t1.ITEM
            AND t2.WAREH = t1.WAREH
            AND t2.COMPANY = t2.COMPANY
        ORDER BY t2.DATE_OUTGO
        FOR XML PATH('')
    ), 1, 1, '')  
) a
CROSS APPLY(
    SELECT DATE_OUTGO = STUFF((
        SELECT ', ' + CAST(t2.DATE_OUTGO AS VARCHAR(10))
        FROM @tempTable t2
        WHERE
            t2.ITEM = t1.ITEM
            AND t2.WAREH = t1.WAREH
            AND t2.COMPANY = t2.COMPANY
        ORDER BY t2.DATE_OUTGO
        FOR XML PATH('')
    ), 1, 1, '')  
) b
GROUP BY
    t1.ITEM, t1.WAREH, t1.COMPANY, a.DIFF_QTY, b.DATE_OUTGO

【讨论】:

    【解决方案3】:
    DECLARE @tempTable TABLE (
        ITEM nvarchar(32),
        DIFF_QTY nvarchar(6), 
        DATE_OUTGO nvarchar(10),
        WAREH nvarchar(5),
        COMPANY nvarchar(5)
    )
    
    INSERT INTO @tempTable (ITEM, DIFF_QTY, DATE_OUTGO, WAREH, COMPANY)
    VALUES 
    (1000, '-5', '2017-08-01', 'WH', 'CMP'),
    (1000, '-3', '2017-08-02', 'WH', 'CMP'),
    (1000, '-4', '2017-08-03', 'WH', 'CMP'),
    (1001, '-10', '2017-08-01', 'WH', 'CMP'),
    (1001, '-13', '2017-08-03', 'WH', 'CMP')
    
    SELECT * 
    FROM @tempTable
    
    DECLARE @itemNum nvarchar(32)
    DECLARE @diffQty nvarchar(max)
    DECLARE @dateOutgo nvarchar(max)
    DECLARE @warehouse nvarchar(5)
    DECLARE @company nvarchar(5)
    
    SET @diffQty = ''
    SET @dateOutgo = ''
    
    
    
    SELECT distinct  ITEM , 
    
                  STUFF((SELECT ', ' + CAST(DIFF_QTY AS NVARCHAR(MAX)) [text()]
             FROM  @tempTable temp
             where t.ITEM=temp.ITEM                                         
             FOR XML PATH(''), TYPE)
            .value('.','NVARCHAR(MAX)'),1,2,'')  DIFF_QTY, 
    
                          STUFF((SELECT ', ' + CAST(DATE_OUTGO AS NVARCHAR(MAX)) [text()]
             FROM  @tempTable temp      
              where t.ITEM=temp.ITEM                                   
             FOR XML PATH(''), TYPE)
            .value('.','NVARCHAR(MAX)'),1,2,'')  DATE_OUTGO,
            WAREH,COMPANY
            from @tempTable t
    

    希望它完全符合您的要求

    【讨论】:

    • 它给出了正确的输出,但与其他解决方案相比非常慢。还是谢谢!
    猜你喜欢
    • 2017-02-16
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 2021-01-07
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    相关资源
    最近更新 更多