通过逗号分隔并将多行分组到一个单元格

时间:2017-08-31 13:02:06

标签: sql sql-server

我知道标题是暧昧的,我知道这里有类似的问题。我看起来并没能完全按照我的需要做任何事情。

我需要Group By ReportNumber和共享一个类别的人添加到一个单元格。

我的数据库:

  ID  |      CategorySymbol    |     ReportNumber   |   NumberInCategory    

   1             A                       31                101
   2             B                       31                107
   3             C                       31                121
   4             A                       32                191
   5             A                       33                165
   6             B                       32                156
   7             C                       32                127
   8             A                       31                166
   9             B                       31                177

期望的结果:

  ReporNumber  |         CategoryA         |       CategoryB        |     CategoryC       

   31                      **101,166**                   **107,177**                121
   32                      191                       156                    127
   33                      165                       NULL                   NULL

许多不同尝试之一:

select ReportNumber,
  CategoryFirst, CategorySecond, CategoryThird, CategoryFourth
from
(
  select NumberInCategory, Report.value('(/Report/@ReportNumber)[1]', 'nvarchar(max)') AS ReportNumber,
    'Category' + cast(CategorySymbol as varchar(10)) CategorySymbol
  from dbo.ReportDB t
) d
pivot
(
    max(NumberInCategory)
  for CategorySymbol in (CategoryFirst, CategorySecond, CategoryThird, CategoryFourth)
) piv;

我的结果:

  ReporNumber  |         CategoryA         |       CategoryB        |     CategoryC       

   31                      **166**                       **177**                    121
   32                      191                       156                    127
   33                      165                       NULL                   NULL

很明显为什么结果是这样的 - max(NumberInCategory)。唯一的问题是如何根据for循环中的CategorySymbol进行选择Number的查询。我尝试做一些功能,返回一个结果,如STUFF或简单的SELECT,但无法正确执行。它不允许我替换max(NumberInCategory)。

E.g。类似的东西:

STUFF((SELECT ', ' + CAST(NumberInCategory AS VARCHAR(10)) [text()], Report.value('(/Report/@ReportNumber)[1]', 'nvarchar(max)') AS ReportNumber
         FROM ReportDB
         WHERE ReportNumber = t.ReportNumber
         FOR XML PATH(''), TYPE)
        .value('.','NVARCHAR(MAX)'),1,2,' ') List_Output

2 个答案:

答案 0 :(得分:6)

pivot()之前使用stuff() with select ... for xml path ('') method of string concatenation

;with t as (
  select 
      NumberInCategory
    , Report.value('(/Report/@ReportNumber)[1]', 'nvarchar(max)') AS ReportNumber
    , CategorySymbol
  from dbo.ReportDB
)
select ReportNumber, CategoryA, CategoryB, CategoryC
from (
  select
      t.ReportNumber
    , CategorySymbol = 'Category'+convert(varchar(10),t.CategorySymbol)
    , NumberInCategory = stuff((
        select ', '+convert(varchar(13),i.NumberInCategory)
        from t i
        where i.ReportNumber = t.ReportNumber
          and i.CategorySymbol = t.CategorySymbol
        order by i.NumberInCategory
        for xml path (''), type).value('(./text())[1]','nvarchar(max)')
      ,1,2,'')
  from t
  group by t.ReportNumber, t.CategorySymbol
  ) s
  pivot (max(NumberInCategory)
    for CategorySymbol in (CategoryA, CategoryB, CategoryC)
  ) piv;

rextester演示:http://rextester.com/OSAZ69656

返回:

+--------------+-----------+-----------+-----------+
| ReportNumber | CategoryA | CategoryB | CategoryC |
+--------------+-----------+-----------+-----------+
|           31 | 101, 166  | 107, 177  | 121       |
|           32 | 191       | 156       | 127       |
|           33 | 165       | NULL      | NULL      |
+--------------+-----------+-----------+-----------+

答案 1 :(得分:1)

这是一种略有不同的味道......

IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL 
DROP TABLE #TestData;

CREATE TABLE #TestData (
    ID INT NOT NULL PRIMARY KEY CLUSTERED,
    CategorySymbol CHAR(1) NOT NULL,
    ReportNumber int NOT NULL,
    NumberInCategory INT NOT NULL 
    );
INSERT #TestData(ID, CategorySymbol, ReportNumber, NumberInCategory) VALUES
    (1, 'A', 31, 101),
    (2, 'B', 31, 107),
    (3, 'C', 31, 121),
    (4, 'A', 32, 191),
    (5, 'A', 33, 165),
    (6, 'B', 32, 156),
    (7, 'C', 32, 127),
    (8, 'A', 31, 166),
    (9, 'B', 31, 177);

-- SELECT * FROM #TestData td;

--==================================================================================

SELECT 
    td1.ReportNumber,
    CategoryA = MAX(CASE WHEN td1.CategorySymbol = 'A' THEN STUFF(c.CSV, 1, 1, '') END),
    CategoryB = MAX(CASE WHEN td1.CategorySymbol = 'B' THEN STUFF(c.CSV, 1, 1, '') END),
    CategoryC = MAX(CASE WHEN td1.CategorySymbol = 'C' THEN STUFF(c.CSV, 1, 1, '') END)
FROM
    #TestData td1
    CROSS APPLY (
                (SELECT 
                    CONCAT(',', td2.NumberInCategory)
                 FROM
                    #TestData td2
                WHERE 
                    td1.CategorySymbol = td2.CategorySymbol
                    AND td1.ReportNumber = td2.ReportNumber
                FOR XML PATH(''))
                ) c (CSV)
GROUP BY
    td1.ReportNumber;

结果...

ReportNumber CategoryA  CategoryB  CategoryC
------------ ---------- ---------- ----------
31           101,166    107,177    121
32           191        156        127
33           165        NULL       NULL