【问题标题】:SQL query to split a column based on hardcoded values用于根据硬编码值拆分列的 SQL 查询
【发布时间】:2013-02-05 20:16:17
【问题描述】:

我有一张桌子,例如假设这个设置

MyTable 有各种列 IdUserId、col1、col2 col3,包括名为 Stuff 的列。

我想通过查询从 MyTable 中输出某些列 但我想拆分“Stuff”列,以便在查询中显示 2 个新列

我可以定义硬编码的类别,我不确定如何在 sql 中表示

Categoy1 = "alpha, bravo, delta, gamma';
Categoy2 = "charlie, echo, hotel';



MyTable

ID |    UserID |      Stuff       | Other Cols....
----------------------------------------------------------
1          1          alpha
2          2          hotel
3          1          charlie
4          1          echo
5          1          gamma
6          2          bravo
7          2          delta

我希望显示选择查询

UserId  |  Category1           |  Catergory2
----------------------------------------------------------
1            alpha, gamma            charlie, echo
---------------------------------------------------------
2            bravo, delta            hotel
----------------------------------------------------------

即根据 stuff 列是否包含 category1 或 category2 中的项目生成 2 列 基于不同的 userId,类别内容可以用逗号分隔,如上所示

请你说明如何做到这一点

希望这是有道理的。

谢谢

【问题讨论】:

  • 分类是否限制为2个?
  • 没有任何一个类别是有限的

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


【解决方案1】:

您可以使用 xml 扩展来连接字符串,然后将类别硬编码到每个子查询中:

CREATE TABLE #T (ID INT, UserID INT, [Stuff] VARCHAR(300))
INSERT #T VALUES
    (1, 1, 'alpha'),
    (2, 2, 'hotel'),
    (3, 1, 'charlie'),
    (4, 1, 'echo'),
    (5, 1, 'gamma'),
    (6, 2, 'bravo'),
    (7, 2, 'delta');

SELECT  UserID,
        [Category1] = STUFF((   SELECT  ', ' + [Stuff]
                                FROM    #T t2
                                WHERE   [Stuff] IN ('alpha', 'bravo', 'delta', 'gamma')
                                AND     t.UserID = t2.UserID
                                FOR XML PATH(''), TYPE
                            ).value('.', 'NVARCHAR(MAX)'), 1, 2, ''),
        [Category2] = STUFF((   SELECT  ', ' + [Stuff]
                                FROM    #T t2
                                WHERE   [Stuff] IN ('charlie', 'echo', 'hotel')
                                AND     t.UserID = t2.UserID
                                FOR XML PATH(''), TYPE
                            ).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
FROM    (   SELECT  DISTINCT UserID
            FROM    #T
        ) t

Example on SQL Fiddle

您可以在一开始就在 CTE (Categories) 中定义您的类别以提高可读性:

WITH Categories AS
(   SELECT  Category, Name
    FROM    (VALUES
                (1, 'alpha'), 
                (1, 'bravo'), 
                (1, 'delta'), 
                (1, 'gamma'),
                (2, 'charlie'),
                (2, 'echo'), 
                (2, 'hotel')
            ) t (Category, Name)
), Data AS
(   SELECT  UserID, [Stuff], Category
    FROM    T
            INNER JOIN Categories c
                ON c.Name = T.[Stuff]
)
SELECT  UserID,
        [Category1] = STUFF((   SELECT  ', ' + [Stuff]
                                FROM    Data t2
                                WHERE   Category = 1
                                AND     t.UserID = t2.UserID
                                FOR XML PATH(''), TYPE
                            ).value('.', 'NVARCHAR(MAX)'), 1, 2, ''),
        [Category2] = STUFF((   SELECT  ', ' + [Stuff]
                                FROM    Data t2
                                WHERE   Category = 2
                                AND     t.UserID = t2.UserID
                                FOR XML PATH(''), TYPE
                            ).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
FROM    (   SELECT  DISTINCT UserID
            FROM    T
        ) t

Example on SQL Fiddle

【讨论】:

  • 很好的答案,我要试一试,有什么办法可以在此之外定义 2 个类别吗?
  • xml 扩展需要什么?我收到一个错误“关键字“FOR”附近的语法不正确。”
  • 你应该什么都不需要,你用的是什么方法?
  • 是的。它将一个值插入到指定位置的字符串中,所以当我完成STUFF((SELECT...), 1, 2, '') 后,它会在后面的字符之间插入“”并替换 2 个字符。这将删除连接字符串开头的逗号。
【解决方案2】:

我的尝试,我从 Stack Overflow 中学到的技术!...请检查:

DECLARE @Categoy1 NVARCHAR(MAX) = 'alpha, bravo, delta, gamma',
        @Categoy2 NVARCHAR(MAX) = 'charlie, echo, hotel'
SELECT 
    UserID,      
    STUFF((SELECT  ', ' + display_term
       FROM sys.dm_fts_parser('"'+ ',' + @Categoy1  + '"', 1033, NULL, 0) INNER JOIN 
            YourTable T on display_term=[Stuff]
            WHERE T.UserID= x.UserID
        FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') Category1,
    STUFF((SELECT  ', ' + display_term
       FROM sys.dm_fts_parser('"'+ ',' + @Categoy2  + '"', 1033, NULL, 0) INNER JOIN 
            YourTable T on display_term=[Stuff]
            WHERE T.UserID= x.UserID
        FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') Category2
FROM YourTable x
GROUP BY UserID

【讨论】:

  • 这是对函数sys.dm_fts_parser的很好使用,但它也似乎是多余的,为什么要硬编码需要函数以获取正确格式的东西?将其硬编码为所需格式更容易。另外在使用XML扩展连接字符串时最好使用.value,如果文本中有任何特殊字符,上述方法将转义它们(例如“>”),而使用.value将保留它们。跨度>
  • 是的...感谢@GarethD 通知...复制时发生了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-27
  • 1970-01-01
  • 2017-07-01
相关资源
最近更新 更多