2010-11-03 8 views
5

Fondamentalmente sto cercando di ottenere un conteggio distinto all'interno di questo risultato a cubetti. Ma sfortunatamente non puoi usare Count (distinto (Campo)) con cubo e rollup (as stated here)SQL Sever Ottenere un conteggio distinto usando "Raggruppa per ... con cubo"

Ecco come appare il dato. (Questo è solo un semplice esempio mi aspetto i duplicati nei dati)

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 

Ecco quello che mi piacerebbe fare, ma non funziona.

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

so che posso fare un sub selezionare come questo per ottenere i risultati che voglio:

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 

Ma questo corre lento quando il set di risultati è grande a causa della sub-select. C'è un altro modo per ottenere un Distinct Count da un risultato a cubetti?

questo è il risultato che voglio vedere

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 

risposta

6

Dovreste essere in grado di ripulire la vostra risposta "disordinato" in questo modo:

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 

Poi l'altra opzione mi si avvicinò con:

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 

Il rendimento può variare in base sugli indici, numero di colonne raggruppate, ecc. Per la tabella di prova che ho scritto, la sotto-selezione e join (al contrario delle Unions) era leggermente migliore.Al momento non ho accesso a un'istanza di MSSQL 2000 (ho eseguito il test su un'istanza del 2005), ma non penso che qui non sia valido.

UPDATE

Un'opzione ancora migliore, specialmente se si sta raggruppando su più di 2 colonne (Se stai raggruppamento su 8 colonne del codice di cui sopra richiederebbe 256 uniscono clausole di catturare tutte le combinazioni nulli!):

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 .... Bel approccio ... mi piace. È sicuramente più efficiente dei sindacati. ancora un po 'più disordinato di quanto mi piaccia ma funziona. –

+0

Grazie! È stato un diversivo divertente per il mio venerdì! Penso che ogni soluzione sarà "più disordinata di quanto dovrebbe essere" senza il supporto aggregato distinto ... – chezy525

+0

La tua ultima opzione è la stessa alla fine alla fine, è la più elegante, e sta colpendo i tavoli il minor numero volte per ottenere il risultato. Per quanto posso dire dai miei piani di esecuzione, un indice su Category1, Category2, ItemID farebbe la query il più velocemente possibile. – cairnz

-1

che è molto interessante. Posso eseguire la prima query in SQL Server 2008 R2, tuttavia la documentazione dice che non funzionerà.

Ecco una variante della seconda query che può offrire risultati migliori. Fa il conteggio distinto nella query secondaria e il cubo nella query esterna

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

.. in realtà questo non funziona quando i dati sono duplicati nella tabella. Guarda i dati revisionati nella domanda. Non restituisce ciò che è previsto. –

-1

Che ne dici di questo ??

La query interna restituisce risultati distinti.

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

non è nemmeno valido ... non è possibile avere un elemento nell'elenco di selezione di un gruppo in quanto non è contenuto in una aggregazione o nella clausola group by. –

+0

concordato. Non ho effettivamente testato la query. Se avessi aggiunto la query interna "group by", sarebbe stata un'idea valida? – exiter2000

+0

No it would not..thanks for trying –

-1

Ho la seguente versione:

Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (Intel X86) 2 aprile 2010 15:53:02 Copyright (c) Microsoft Corporation Express Edition con Servizi avanzati in Windows NT 5.1 (Build 2600: service pack 3)

Quando eseguo la query

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

io ottenere questi risultati

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

Code Gunny Sono consapevole che questo funziona su SQL Server 2008. Ma la mia domanda riguarda SQL Server 2000. La tua registrazione è irrilevante –

+0

@John - Suppongo di dover prestare più attenzione a i tag, eh. –

1

Ecco un'altra possibilità che ho trovato ma è estremamente disordinato. Tuttavia funziona più velocemente rispetto all'utilizzo di una sottoselezione.

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 
Problemi correlati