2010-06-21 8 views
9

Comment puis-je retourner deux colonnes utilisant chacune des critères WHERE différents? De toute évidence, cela ne fonctionnera pas:SQL Deux conditions WHERE différentes pour deux colonnes

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 

Ceci est la sortie Je cherche:

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

Vous ne savez pas si cela est possible sans provoquer de conflit dans le jeu de résultats. – VoodooChild

Répondre

12

Si vous spécifiez un nom de colonne pour la fonction COUNT, il ne compte pas les valeurs NULL.

Ainsi, la façon simple serait d'utiliser les instructions CASE pour convertir les valeurs que vous ne souhaitez pas pris en compte à 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 

Je ne suis pas 100% certain que le moteur de recherche vous permettra d'utiliser CASE dans les COUNT (Je ne suis même pas sûr de la plateforme DB que vous utilisez), mais cela vous donne l'idée. Si cette méthode ne fonctionne pas, vous pouvez écrire la requête en utilisant une table dérivée qui vous donnera le même résultat.

+0

Oups, je n'ai pas remarqué que votre "Total" est le nombre mensuel à ce jour. Je vérifie si CASE fonctionne avec COUNT sur le serveur SQL. Je posterai un extrait plus complet quand j'aurai fini. – Toby

+2

Si vous ne voulez pas vous fier au comportement Null, vous pouvez toujours avoir l'instruction case return 1 ou 0 et faire une somme au lieu d'un nombre. – JohnFx

+0

@JohnFx: Oui, cela fonctionne aussi. En fonction de la définition de la table, j'écris parfois les deux et je teste la performance si je sais que je vais traiter de grands ensembles. – Toby

0

Vous pouvez probablement utiliser l'instruction MySQL IF sur le COUNT

1

Cela semble être une bonne situation pour 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 

Fondamentalement, vous effectuez les deux requêtes séparément, puis en les combinant en un seul ensemble.

Vous ne savez pas quel type de base de données vous utilisez mais voici les liens pour SQL Server et MySql.

+0

Um, non.Cela se traduit par 2 lignes, bien en fait une erreur dans la plupart des DB. Besoin de regrouper par nom ... après cela vous obtiendrez deux rangées. Une ligne aura la valeur correcte pour Total et la valeur incorrecte pour YeartoDate, l'autre ligne sera l'inverse. N'utilisez jamais UNION lorsque vous savez que vous avez deux ensembles de résultats différents. UNION force une sorte, UNION ALL ne fonctionne pas. Oui c'est juste deux rangs ... c'est juste une mauvaise habitude. Utilisez UNION ALL tout le temps et supprimez le ALL lorsque vous avez besoin d'un travail supplémentaire. –

1

Vous pouvez également utiliser

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 jointure externe complète est pas nécessaire, mais démontre à quel point vous pourriez avoir besoin pour traiter un cas où un ensemble n'est pas un sous-ensemble strict de l'autre. J'utiliserais généralement la sous-requête YFT LEFT JOIN pour la sous-requête du mois en cours.

Une autre stratégie - avec 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: Cela devrait fonctionner dans 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

Une description pourrait aider cette réponse ... – Craig

Questions connexes