【问题标题】:Combine different rows to one using the similar column values of one column使用一列的相似列值将不同的行合并为一
【发布时间】:2021-12-23 14:05:26
【问题描述】:

我希望根据类似的特定列值合并所有列。

假设我在 "DeckName" 中有类似的值,所以使用 Column2 我希望将所有不同的其他列值合并为一个。

输入表:

DeckId     DeckName   Location   Items     Places   UserName

XK001      NOVA        USA       Cream     ASIA-P   NOVA001
XK002      NOVA        IND       DEO       AFRICA   NOVA002
XK001      NOVA        USA       Cosmetic  ASIA-P   NOVA003
VK001      VEET        RUS       PROFIX    UK       VEET001
VK003      VEET        CHI       Cream     ASIA-P   VEET002
VK002      VEET        NED       WAX       RUSSIA   VEET001
NS001      PHLIPS      USA       Cream     ASIA-P   PHLPS001
PS001      RUDS        USA       Cream     ASIA-P   VLT001

预期输出表值

 DeckId                DeckName   Location       Items                 Places              UserName
XK001; XK002           NOVA       USA; IND       Cream; DEO; Cosmetic  ASIA-P; AFRICA      NOVA001; NOVA002; NOVA003
VK001; VK003; VK002    VEET       RUS; CHI; NED  PROFIX; Cream; WAX    UK; ASIA-P; RUSSIA  VEET001; VEET002
NS001                  PHLIPS     USA            Cream                 ASIA-P              PHLPS001
PS001                  RUDS       USA            Cream                 ASIA-P              VLT001

请提出查询以找到预期结果:

【问题讨论】:

  • 请只标记您真正使用的RDBMS。虽然有 大量 示例说明如何在 SQL Server 和 MySQL 中聚合字符串,如果您有快速搜索的话。 1000 个例子你不明白怎么办?你的尝试是什么?为什么他们不工作?
  • 您在这里使用的是哪个数据库? Oracle 语法与 SQL Server 不同
  • @NNM - 我正在使用 SQL Server 数据库
  • 另外,我真的希望 DeckID 不是钥匙
  • @Alan - 是的 DeckID 不是密钥

标签: sql-server


【解决方案1】:

你是否在尝试类似的东西:

select STRING_AGG(DeckId,';') as DeckId , 
       DeckName , 
       STRING_AGG(Location,';') as Location,
       STRING_AGG(Items,';') as Items,
       STRING_AGG(Places,';') as Places,
       STRING_AGG(UserName,';') as UserName
from  test_tbl
group by DeckName;

演示:https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=ece626d2ce2919c2148cccbe83e4634e

查看更多信息:https://docs.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15

对于较旧的 SQL Server 版本,可能不是最佳解决方案,但您可以尝试:

SELECT DISTINCT ST2.DeckName, 
    SUBSTRING(
        (
            SELECT ';'+DeckId  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [DeckId],
        
      SUBSTRING(
        (
            SELECT ';'+Location  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [Location]  ,
        
      SUBSTRING(
        (
            SELECT ';'+Items  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [Items]  , 
        
      SUBSTRING(
        (
            SELECT ';'+Places  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [Places]  ,
        
     SUBSTRING(
        (
            SELECT ';'+UserName  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [UserName]  
        
FROM test_tbl ST2

演示:https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=53aef222b43a50f6e4874e3b307a018b

【讨论】:

  • 我建议使用STUFF 来删除SUBSTRING 上的前导分隔符。这将导致超过 1000 个字符的值被截断(STUFF 不会)。
  • @Ergest Basha - 感谢您的回答,但 DeckID、Items 和其他列的类似列值也被分开。任何解决方案。
  • @Manz 如果你在这个小提琴中添加不同的东西:dbfiddle.uk/… ?
【解决方案2】:

您使用的是哪个版本的 SQL Server?

如果您使用的是 2017 及以上版本,则可以在 sql server 中使用 string_agg 函数(与 Oracle 中的 listagg 相同)。像下面这样 -

select deck_name, 
        STRING_AGG(deck_id, ';') within group(order by deck_name) as deck_id,
        STRING_AGG(Location, ';') within group(order by deck_name) as location,
        STRING_AGG(items, ';') within group(order by deck_name) as items,
        STRING_AGG(places, ';') within group(order by deck_name) as place,
        STRING_AGG(username, ';') within group(order by deck_name) as username
from deck_table dt
group by deck_name

对于旧版本,您必须使用带有 XML 路径的 STUFF 函数。我无法运行它,您可能不得不使用 XML 表达式,但您可以尝试如下所示 -

select deck_name, 
        STUFF((
       SELECT distinct ';' + dt1.deck_id
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.deck_id
          FOR XML PATH('')), 1, LEN(','), '') AS deck_id,
          STUFF((
       SELECT distinct ';' + dt1.location
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.location
          FOR XML PATH('')), 1, LEN(','), '') AS location,
          STUFF((
       SELECT distinct ';' + dt1.items
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.items
          FOR XML PATH('')), 1, LEN(','), '') AS items,
          STUFF((
       SELECT distinct ';' + dt1.place
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.place
          FOR XML PATH('')), 1, LEN(','), '') AS place,
          STUFF((
       SELECT distinct ';' + dt1.username
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.username
          FOR XML PATH('')), 1, LEN(','), '') AS username
from deck_table dt
group by deck_name

【讨论】:

  • 感谢您的回答,但我使用的是 SQL Server 2014 版,由于 STRING_AGG 不适用于它,任何其他方法来解决它
  • 我已经用 STUFF 函数更新了我的答案。
  • 感谢您的建议,但对于 DeckID、Items 和其他列,类似的列值也将分开。例如,对于 Column DeckID - XK001; XK002;XK001 代替 XK001; XK002 有什么建议
  • 你应该能够在 STUFF 中区分 - SELECT distinct ';' + dt1.deck_id。我也会在查询中更新
  • 如果指定了 SELECT DISTINCT,则出现错误“消息 145,级别 15,状态 1,第 16 行 ORDER BY 项目必须出现在选择列表中。”
猜你喜欢
  • 2023-03-15
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-25
  • 2019-05-24
  • 2020-05-19
相关资源
最近更新 更多