Actualmente, estoy usando group by en una tabla con datos de muestra a continuación y sumando los valores totales.

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    

Ahora lo que quiero es escribir una consulta que pueda mostrar los rangos de ID en una columna separada a continuación es el resultado deseado

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

PD: los datos reales son grandes, por favor sugiera una solución óptima

0
Syed Atir Mohiuddin 10 sep. 2018 a las 13:43

3 respuestas

La mejor respuesta

Suponiendo que la ID es continua, simplemente puede obtener los MIN() y MAX() por grupo

-- 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
*/
2
Squirrel 10 sep. 2018 a las 11:01

Ha especificado que los ID son consecutivos. Sin embargo, no tendré en cuenta esta suposición y numeraré los grupos con LAG y 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)

Resultado:

| Type    | Quantity | IDRange |
|---------|----------|---------|
| SampleA | 48       | 1-4,7   |
| SampleB | 17       | 5-6     |
2
Salman A 10 sep. 2018 a las 12:15

Un espacio en la secuencia de id devolverá un elemento de conjunto de datos adicional en el rango de ID usando esta sintaxis, necesita sql-server 2012 para usar esta sintaxis debido a la función 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

Resultado:

Type    Total(Sum)  ID Range
sampleA         48  1-4, 7
sampleB         17  5-6
2
t-clausen.dk 10 sep. 2018 a las 11:22