2010-11-03 6 views
5

Básicamente estoy tratando de obtener un recuento distinto dentro de este resultado en cubos. Pero, desafortunadamente, no puede usar Count (distinct (Field)) con cubos y rollup (as stated here)SQL Sever Obteniendo una cuenta diferente usando "Agrupar por ... Con cubo"

Esto es lo que parecen los datos. (Esto es sólo un ejemplo sencillo que se puede esperar duplicados en los datos)

Category1  Category2  ItemId 
    a    b    1 
    a    b    1 
    a    a    1 
    a    a    2 
    a    c    1 
    a    b    2 
    a    b    3 
    a    c    2 
    a    a    1 
    a    a    3 
    a    c    4 

Esto es lo que me gustaría hacer, pero no funciona.

SELECT 
    Category1, 
    Category2, 
    Count(Distinct(ItemId)) 
FROM ItemList IL 
GROUP BY 
    Category1, 
    Category2 
WITH CUBE 

sé que puedo hacer un sub seleccionar como este para obtener los resultados que quiero:

SELECT 
    *, 
    (SELECT 
    Count(Distinct(ItemId)) 
    FROM ItemList IL2 
    WHERE 
    (Q1.Category1 IS NULL OR Q1.Category1 IS NOT NULL AND Q1.Category1 = IL2.Category1) 
    AND 
    (Q1.Category2 IS NULL OR Q1.Category2 IS NOT NULL AND Q1.Category2 = IL2.Category2)) 
     AS DistinctCountOfItems 
FROM (SELECT 
     Category1, 
     Category2 
     FROM ItemList IL 
     GROUP BY 
     Category1, 
     Category2 
     WITH CUBE) Q1 

Pero esto corre lento cuando el conjunto de resultados es grande debido a la sub-select. ¿Hay alguna otra forma de obtener un Recuento Distinto a partir de un resultado en cubos?

Este es el resultado que quiero ver

Category1  Category2 DistinctCountOfItems 
a    a   3 
a    b   3 
a    c   3 
a    NULL   4 
NULL   NULL   4 
NULL   a   3 
NULL   b   3 
NULL   c   3 

Respuesta

6

Usted debe ser capaz de limpiar su respuesta "sucio" de esta manera:

select Category1, Category2, count(distinct ItemId) 
from ItemList 
group by Category1, Category2 
UNION ALL 
select Category1, null, count(distinct ItemId) 
from ItemList 
group by Category1 
UNION ALL 
select null, Category2, count(distinct ItemId) 
from ItemList 
group by Category2 
UNION ALL 
select null, null, count(distinct ItemId) 
from ItemList 

A continuación, la otra opción que se me ocurrió:

select IL1.Category1, IL1.Category2, count(distinct ItemId) 
from ( 
    select Category1, Category2 
    from ItemList 
    group by Category1, Category2 
    with cube 
) IL1 
join ItemList IL2 on (IL1.Category1=IL2.Category1 and IL1.Category2=IL2.Category2) 
     or (IL1.Category1 is null and IL1.Category2=IL2.Category2) 
     or (IL1.Category2 is null and IL1.Category1=IL2.Category1) 
     or (IL1.Category1 is null and IL1.Category2 is null) 
group by IL1.Category1, IL1.Category2 

El rendimiento puede variar en función en los índices, el número de columnas que se agrupan, etc. Para la tabla de prueba que escribí, la selección secundaria y la combinación (a diferencia de las Uniones) fue ligeramente mejor.No tengo acceso a una instancia de MSSQL 2000 en este momento (lo probé en una instancia de 2005), pero no creo que nada aquí no sea válido.

ACTUALIZACIÓN

Una mejor opción, especialmente si se está agrupando en más de 2 columnas (Si va a agrupar en 8 columnas el código anterior requeriría 256 se unen a las cláusulas de atrapar todas las combinaciones nulos!):

select IL1.Category1, IL1.Category2, count(distinct ItemId) 
from ( 
    select Category1, Category2 
    from ItemList 
    group by Category1, Category2 
    with cube 
) IL1 
inner join ItemList IL2 on isnull(IL1.Category1,IL2.Category1)=IL2.Category1 
        and isnull(IL1.Category2,IL2.Category2)=IL2.Category2 
group by IL1.Category1, IL1.Category2 
+0

@ chezy525 .... Buen enfoque ... me gusta. Definitivamente es más eficiente que los sindicatos. todavía un poco más desordenado de lo que me gusta, pero funciona. –

+0

Gracias! ¡Esta fue una diversión divertida para mi viernes! Creo que cualquier solución va a ser "más desordenada de lo que debería ser" sin el agregado de soporte agregado ... – chezy525

+0

Su última opción es la misma con la que finalmente termino, es la más elegante, y está llegando a las mesas lo menos posible veces para recuperar el resultado. Por lo que puedo decir de mis planes de ejecución, un índice en Category1, Category2, ItemID haría la consulta lo más rápido posible. – cairnz

-1

Eso es muy interesante. Puedo ejecutar su primera consulta en SQL Server 2008 R2, pero la documentación dice que no funcionará.

Aquí hay una variación de su segunda consulta que puede tener un mejor rendimiento. Hace el recuento distinto en la consulta secundaria y el cubo en la consulta externa

SELECT Category1, Category2, MAX(DistinctCount) as DistinctCount 
FROM (
    SELECT Category1, Category2, COUNT(DISTINCT ItemId) as DistinctCount 
    FROM ItemList 
    GROUP BY Category1, Category2 
    ) Q1 
GROUP BY Category1, Category2 
WITH CUBE 
+0

.. en realidad, esto no funciona cuando los datos están duplicados en la tabla. Mira los datos revisados ​​en la pregunta. No devuelve lo que se espera. –

-1

¿Qué tal esto?

La consulta interna arrojaría resultados distintos.

SELECT ORIGINAL_ITEM.Category1, DISTINCT_ITEM.Category2, DISTINCT_ITEM.cnt 
FROM 
    (SELECT DISTINCT category2, COUNT(*) as CNT 
    FROM ItemList) DISTINCT_ITEM 
JOIN ItemList ORIGINAL_ITEM on ORIGINAL_ITEM.category2 = DISTINCT_ITEM.category2 
GROUP BY ORIGINAL_ITEM.category1, DISTINCT_ITEM.category2 
+0

esto ni siquiera es válido ... no puede tener un elemento en la lista de selección de un grupo por el que no está contenido en una cláusula aggregate o group by. –

+0

De acuerdo. En realidad, no probé la consulta. Así que si agregué la consulta interna "grupo por", ¿sería una idea válida? – exiter2000

+0

No, no ... gracias por probar –

-1

Tengo la siguiente versión:

Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (Intel X86) 2 Abr 2010 15:53:02 Derechos de autor (c) Microsoft Corporation Express Edition con Servicios avanzados en Windows NT 5.1 (Build 2600: Service pack 3)

Cuando ejecuto la consulta

SELECT 
    Category1, 
    Category2, 
    COUNT(DISTINCT(ItemId)) 
FROM ItemList IL 
GROUP BY 
    Category1, 
    Category2 
WITH CUBE 

puedo obtener estos resultados

a  a  3 
a  b  3 
a  c  3 
NULL a  3 
NULL b  3 
NULL c  3 
a  NULL 4 
NULL NULL 4 
+0

Código Gunny Soy consciente de que esto funciona en SQL Server 2008. Pero mi pregunta es respecto a SQL Server 2000. Su publicación es irrelevante –

+0

@John - Creo que debo prestar más atención a las etiquetas, eh. –

1

Aquí hay otra posibilidad que encontré pero es extremadamente desordenada. Sin embargo, se ejecuta más rápido que utilizando una subselección.

SELECT 
    category1, 
    category2, 
    count(distinct itemid) 
FROM (SELECT DISTINCT 
     category1, 
     category2, 
     itemid 
     FROM ItemList 
) x 
GROUP BY category1, category2 
UNION ALL 
SELECT 
    category1, 
    NULL, 
    count(distinct itemid) 
FROM (SELECT DISTINCT 
     category1, 
     category2, 
     itemid 
     FROM ItemList 
) x 
GROUP BY category1 
UNION ALL 
SELECT 
    NULL, 
    category2, 
    count(distinct itemid) 
FROM (SELECT DISTINCT 
     category1, 
     category2, 
     itemid 
     FROM ItemList 
) x 
GROUP BY category2 
UNION ALL 
SELECT 
    NULL, 
    NULL, 
    count(distinct itemid) 
FROM (SELECT DISTINCT 
     category1, 
     category2, 
     itemid 
     FROM ItemList 
) x 
Cuestiones relacionadas