2010-06-21 32 views
9

¿Cómo puedo devolver dos columnas que cada una utiliza diferente DONDE critia? Obviamente, esto no funcionará:SQL Dos condiciones WHERE diferentes para dos columnas

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 

Ésta es la salida Busco:

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

No estoy seguro si eso es posible sin obtener un conflicto en el conjunto de resultados. – VoodooChild

Respuesta

12

Si especifica un nombre de columna para la función COUNT, no cuenta NULL valores.

Por lo tanto, la forma más sencilla sería utilizar las instrucciones CASE para convertir los valores que no desea contados 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 

no estoy 100% seguro de que el motor de consulta le permitirá utilizar caso dentro de COUNT (Ni siquiera estoy seguro de qué plataforma de BD está usando), pero le da la idea. Si esto no funciona, puede escribir la consulta utilizando una tabla derivada que le dará el mismo resultado.

+0

Vaya, no me di cuenta de que su "Total" es el conteo del mes hasta la fecha. Estoy probando para ver si CASE funciona con COUNT en el servidor SQL. Publicaré un fragmento más completo cuando termine. – Toby

+2

Si no quiere confiar en el comportamiento nulo, siempre puede hacer que la declaración case devuelva 1 o 0 y haga una suma en lugar de un conteo. – JohnFx

+0

@JohnFx: Sí, esto también funciona. Dependiendo de la definición de la tabla, a veces escribo ambas y pruebo el rendimiento si sé que trataré con conjuntos grandes. – Toby

0

es probable que pueda usar el MySQL IF A la cuenta

1

Parece una buena situación para UNION.

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 

Básicamente, usted está haciendo las dos consultas por separado y luego combinándolas en un solo conjunto.

No estoy seguro de qué tipo de base de datos está utilizando pero aquí están los enlaces para SQL Server y MySql.

+0

Um, no.Esto resulta en 2 filas, bueno en realidad un error en la mayoría de las bases de datos. Se necesita Group By Name ... después de eso obtendrá dos filas. Una fila tendrá el valor correcto para Total y el valor incorrecto para YeartoDate, la otra fila será al revés. Además, nunca use UNION cuando sabe que tiene dos conjuntos de resultados diferentes. UNIÓN fuerza un tipo, UNIÓN TODO no. Sí, esto es solo dos filas ... es solo un mal hábito. Use UNION ALL todo el tiempo y elimine ALL cuando necesite el trabajo extra realizado. –

1

También puede utilizar

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 

la combinación externa completa no es necesaria, pero sólo demuestra cómo es posible que necesite para manejar un caso en el que un conjunto no es un subconjunto estricto de la otra. Normalmente utilizaría la subconsulta YTD LEFT JOIN para la subconsulta del mes actual.

Otra estrategia - utilizando CASO:

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: Esto debería funcionar en 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 descripción ayudaría a esta respuesta ... – Craig