Группировать и суммировать значения и перечислять последовательные строки в каждой группе - PullRequest
0 голосов
/ 10 сентября 2018

В настоящее время я использую group by в таблице с примерами данных ниже и суммирую итоговые значения.

ID  Type   Quantity
1  sampleA   10
2  sampleA   1
3  sampleA   5
4  sampleA   9
5  sampleB   7
6  sampleB   10
7  sampleA   23

  Type    Total(sum)
Sample A     48      
Sample B     17    

Теперь я хочу написать запрос, который может показать диапазоны идентификаторов в отдельномВ столбце ниже указан желаемый результат

  Type    Total(sum)  ID Range
Sample A     48        1-4, 7
Sample B     17        5-6   

PS: фактические данные велики, пожалуйста, предложите оптимальное решение

Ответы [ 3 ]

0 голосов
/ 10 сентября 2018

Пробел в последовательности идентификаторов вернет дополнительный элемент набора данных в диапазоне идентификаторов с использованием этого синтаксиса, вам необходим sql-server 2012 для использования этого синтаксиса из-за функции CONCAT :

DECLARE @t table(ID int, Type varchar(10), Quantity int)
INSERT @t values(1  ,'sampleA', 10),(2 ,'sampleA',  1),(3 ,'sampleA', 5),
(4 ,'sampleA', 9),(5 ,'sampleB', 7),(6 ,'sampleB', 10),(7 ,'sampleA', 23)

;WITH CTE as
(
  SELECT
    id, Type, sum(quantity) over(partition by Type) ts,
    id - dense_rank() over (partition by Type order by id) grp
  FROM @t
)
SELECT Type, ts [Total(Sum)],
  STUFF((SELECT ', '+ concat(min(id),'-'+cast(nullif(max(id),min(id)) as varchar(20)))
  FROM CTE x
  WHERE Type  = cte.Type
  GROUP BY x.grp  
  FOR xml path ('')  
  ), 1,2,'') [ID Range]
FROM CTE
GROUP BY Type, ts

Результат:

Type    Total(Sum)  ID Range
sampleA         48  1-4, 7
sampleB         17  5-6
0 голосов
/ 10 сентября 2018

Вы указали, что идентификаторы являются последовательными.Тем не менее, я игнорирую это предположение и нумерую группы, используя LAG и SUM...OVER:

WITH yourdata(ID, Type, Quantity) AS (
    SELECT 1, 'SampleA', 10 UNION
    SELECT 2, 'SampleA', 1 UNION
    SELECT 3, 'SampleA', 5 UNION
    SELECT 4, 'SampleA', 9 UNION
    SELECT 5, 'SampleB', 7 UNION
    SELECT 6, 'SampleB', 10 UNION
    SELECT 7, 'SampleA', 23
), cte_change_flag AS (
    SELECT ID, Type, CASE WHEN LAG(Type) OVER (ORDER BY ID) = Type THEN 0 ELSE 1 END AS chg
    FROM yourdata
), cte_group_number AS (
    SELECT ID, Type, SUM(chg) OVER (ORDER BY ID) AS grp
    FROM cte_change_flag
)
SELECT Type, Quantity, STUFF(XMLCol, 1, 1, '') AS IDRange
FROM (
    SELECT Type, SUM(Quantity) AS Quantity
    FROM yourdata
    GROUP BY Type
) AS main_groups
CROSS APPLY (
    SELECT CONCAT(',', MIN(ID), CASE WHEN MIN(ID) <> MAX(ID) THEN CONCAT('-', MAX(ID)) END)
    FROM cte_group_number
    WHERE Type = main_groups.Type
    GROUP BY grp
    FOR XML PATH('')
) AS sub_groups(XMLCol)

Результат:

| Type    | Quantity | IDRange |
|---------|----------|---------|
| SampleA | 48       | 1-4,7   |
| SampleB | 17       | 5-6     |
0 голосов
/ 10 сентября 2018

Если предположить, что идентификатор является непрерывным, то можно просто получить MIN() и MAX() его по группе

-- create the sample table for testing
declare @sample table
(
    ID      int,
    Type        varchar(10),
    Quantity    int
)

-- insert some sample data
insert into @sample 
VALUES
(1,  'sampleA',   10),
(2,  'sampleA',    1),
(3,  'sampleA',    5),
(4,  'sampleA',    9),
(5,  'sampleB',    7),
(6,  'sampleB',   10),
(7,  'sampleA',   23)

-- the query
; with 
cte as
(
    select  *, grp = ID - dense_rank() over(order by Type, ID)
    from    @sample 
),
summary as
(
    select  Type, sum(Quantity) as Total
    from    @sample
    group by Type
)
select  Type, Total, id_range = stuff(id_range, 1, 1, '')
from    summary c
        cross apply
        (
            select  ', ' + convert(varchar(5), min(x.ID)) 
                    + case  when min(x.ID) <> max(x.ID) 
                            then '-' + convert(varchar(5), max(x.ID)) 
                            else '' 
                            end
            from    cte x
            where   x.Type  = c.Type
            group by x.grp  
            for xml path ('')   
        ) r (id_range)

/*  RESULT : 
    Type    Total  id_range
    sampleA    48  1-4, 7
    sampleB    17  5-6
*/
...