2010-06-21 20 views
9

Come posso restituire due colonne che utilizzano ciascuna un criterio WHERE diverso? Ovviamente, questo non funzionerà:SQL Due diverse WHERE Condizioni per due colonne

SELECT Name, COUNT(Column1) AS Total, COUNT(Column1) AS YearToDate 
FROM Table1 
WHERE Occurred_Date BETWEEN '2010-06-01' AND '2010-06-30' --Total 
WHERE Occurred_Date BETWEEN '2010-01-01' AND '2010-06-30' --YearToDate 

Questa è l'uscita che sto cercando:

Name | Total | YTD 
------------------- 
Item1 | 2  | 3 
Item2 | 4  | 8 
+0

Non è sicuro se ciò è possibile senza ottenere un conflitto nel set di risultati. – VoodooChild

risposta

12

Se si specifica un nome di colonna per la funzione COUNT, non conteggia i valori NULL.

Quindi, il modo più semplice sarebbe quella di utilizzare le dichiarazioni CASE per convertire i valori che non si desidera contò fino a NULL

SELECT 
    Name, 
    COUNT(CASE 
      WHEN Occurred_Date >= '2010-01-01' AND Occurred_Date < '2011-01-01' 
       THEN Occurred_Date 
      ELSE NULL 
      END) AS [YTD] 
    COUNT(CASE 
      WHEN Occurred_Date >= '2010-06-01' AND Occurred_Date < '2011-07-01' 
       THEN Occurred_Date 
      ELSE NULL 
      END) AS [MTD] 
FROM Table1 
GROUP BY Name 

Io non sono sicuro al 100% del motore di query vi permetterà di utilizzare comunque entro COUNT (Non sono nemmeno sicuro di quale piattaforma DB stai usando), ma ti dà l'idea. Se in questo modo non funziona, puoi scrivere la query utilizzando una tabella derivata che ti darà lo stesso risultato.

+0

Oops, non ho notato che il tuo "Totale" è il conteggio del mese. Sto testando se CASE funziona con COUNT sul server SQL. Pubblicherò uno snippet più completo quando avrò finito. – Toby

+2

Se non si vuole fare affidamento sul comportamento Null, si può sempre fare in modo che l'istruzione case restituisca 1 o 0 e faccia una somma invece di un conteggio. – JohnFx

+0

@JohnFx: Sì, anche questo funziona. A seconda della definizione della tabella, a volte scrivo entrambe e testiamo le prestazioni se so che avrò a che fare con insiemi di grandi dimensioni. – Toby

0

probabilmente si può usare MySQL istruzione IF sul conteggio

1

Sembra una buona situazione per un'UNIONE.

SELECT Name, COUNT(Column1) AS Total, COUNT(Column1) AS YearToDate 
FROM Table1 
WHERE Occurred_Date BETWEEN '2010-06-01' AND '2010-06-30' --Total 
UNION 
SELECT Name, COUNT(Column1) AS Total, COUNT(Column1) AS YearToDate 
FROM Table1 
WHERE Occurred_Date BETWEEN '2010-01-01' AND '2010-06-30' --YearToDate 

Fondamentalmente si stanno facendo le due query separatamente e quindi combinandole in un unico set.

Non so quale tipo di DB si sta utilizzando, ma qui ci sono i collegamenti per SQL Server e MySql.

+0

Ehm, no.Ciò si traduce in 2 righe, in realtà un errore nella maggior parte dei DB. Necessario Raggruppamento per nome ... dopo che avrai due righe. Una riga avrà il valore corretto per Totale e il valore errato per YeartoDate, l'altra riga sarà il contrario. Inoltre, non utilizzare mai UNION quando sai di avere due set di risultati diversi. UNION costringe un tipo, UNION ALL non lo fa. Sì, questo è solo due righe ... è solo una brutta abitudine. Usa UNION ALL tutto il tempo e rimuovi TUTTO quando hai bisogno del lavoro extra. –

1

è anche possibile utilizzare

SELECT m.count, ytd.count FROM 
    (SELECT COUNT(id) count FROM table WHERE date BETWEEN BETWEEN '2010-06-01' AND '2010-06-30') m, 
    (SELECT COUNT(id) count FROM table WHERE date BETWEEN BETWEEN '2010-01-01' AND '2010-06-30') ytd 
0
SELECT COALESCE(CurrMonth.Name, YTD.Name) AS Name, CurrMonth.Total AS Total, YTD.Total AS YearToDate 
FROM (
    SELECT Name, COUNT(Column1) AS Total 
    FROM Table1 
    WHERE Occurred_Date BETWEEN '2010-06-01' AND '2010-06-30' --Total 
    GROUP BY Name 
) AS CurrMonth 
FULL OUTER JOIN 
(
    SELECT Name, COUNT(Column1) AS Total 
    FROM Table1 
    WHERE Occurred_Date BETWEEN '2010-01-01' AND '2010-06-30' --YearToDate 
    GROUP BY Name 
) AS YTD 
ON CurrMonth.Name = YTD.Name 

Il full outer join non è necessario, ma solo dimostra come potrebbe essere necessario per trattare un caso in cui un insieme non è un sottoinsieme severo dell'altro. In genere utilizzerei la sottoquery YTD LEFT JOIN per la sottoquery del mese corrente.

Un'altra strategia - utilizzando CASE:

SELECT Name 
    ,COUNT(CASE WHEN Occurred_Date BETWEEN '2010-06-01' AND '2010-06-30' THEN Column1 ELSE NULL END) AS Total 
    ,COUNT(CASE WHEN Occurred_Date BETWEEN '2010-01-01' AND '2010-06-30' THEN Column1 ELSE NULL END) AS YearToDate 
FROM Table1 
WHERE Occurred_Date BETWEEN '2010-06-01' AND '2010-06-30' -- (unnecessary) 
    OR Occurred_Date BETWEEN '2010-01-01' AND '2010-06-30' 
GROUP BY Name 
0
SELECT Name 
    ,SUM(
     CASE WHEN Occurred_Date BETWEEN '2010-06-01' AND '2010-06-30' 
     THEN 1 
     ELSE 0 
     END) AS Total 
    ,SUM(
     CASE WHEN Occurred_Date BETWEEN '2010-01-01' AND '2010-06-30' 
     THEN 1 
     ELSE 0 
     END) AS YearToDate 
FROM Table1 
GROUP BY Name 

EDIT: Questo dovrebbe funzionare in SQL Server.

0
SELECT DISTINCT m.field1, b.field2, 

      SUM (CASE 
        WHEN m.created_on >= 
             TO_DATE ('15/11/2012', 'DD/MM/YYYY') 
        AND m.created_on < 
            TO_DATE ('15/11/2012', 'DD/MM/YYYY') 
            + 1 
         THEN 1 
        ELSE 0 
       END 
       ) AS count1, 
      COUNT (1) AS count2 
     FROM table1 m, table2 b 
     WHERE m.field1 IN (SELECT DISTINCT field1 
            FROM table1) 
     AND b.field1 = m.field1 
    GROUP BY m.field1, b.field2 
    ORDER BY count2 DESC; 
+0

Una descrizione potrebbe aiutare questa risposta ... – Craig

Problemi correlati