2013-07-23 4 views
11

Ich bin auf der Suche, ob es einen besseren Ansatz für die Abfrage unten gibt. Ich versuche, einen zusammenfassenden Bericht zu erstellen, der Statistiken nach Datum zusammenstellt.SQL-Abfrage - SUMME (CASE WHEN x THEN 1 ELSE 0) für mehrere Spalten

SELECT CAST(Detail.ReceiptDate AS DATE) AS 'DATE' 
, SUM(CASE WHEN Detail.Type = 'TotalMailed' THEN 1 ELSE 0 END) AS 'TOTALMAILED' 
, SUM(CASE WHEN Detail.Type = 'TotalReturnMail' THEN 1 ELSE 0 END) AS 'TOTALUNDELINOTICESRECEIVED' 
, SUM(CASE WHEN Detail.Type = 'TraceReturnedMail' THEN 1 ELSE 0 END) AS 'TRACEUNDELNOTICESRECEIVED' 
FROM 
(
select SentDate AS 'ReceiptDate', 'TotalMailed' AS 'Type' 
from MailDataExtract 
where sentdate is not null 
UNION ALL 
select MDE.ReturnMailDate AS 'ReceiptDate', 'TotalReturnMail' AS 'Type' 
from MailDataExtract MDE 
where MDE.ReturnMailDate is not null 
UNION ALL 
select MDE.ReturnMailDate AS 'ReceiptDate', 'TraceReturnedMail' AS 'Type' 
from MailDataExtract MDE 
    inner join DTSharedData.dbo.ScanData SD ON SD.ScanDataID = MDE.ReturnScanDataID 
where MDE.ReturnMailDate is not null AND SD.ReturnMailTypeID = 1 
) AS Detail 
GROUP BY CAST(Detail.ReceiptDate AS DATE) 
ORDER BY 1 

Dies ist nur ein Beispiel für die Abfrage ist (die in einem Bericht verwendet wird) als eine Reihe von anderen Spalten und die Logik für die anderen Statistiken gibt es sind viel komplizierter. Gibt es einen eleganteren Ansatz, um diese Art von Informationen zu erhalten?

+0

Ist das in einem proc oder Blick, oder etwas anderes? Grundsätzlich können Sie Variablen einführen und mehrere Anweisungen ausführen, oder ist es nur eine große 'select' Anweisung? –

+0

Es ist ein Proc, der für einen SSRS-Bericht verwendet wird, also muss es im Wesentlichen eine Select-Anweisung sein, da ich eine Ergebnismenge zurückgeben muss (richtig?) – MickJuice

+0

Ja, Sie haben schließlich eine große Auswahl an der end, aber da es sich um einen proc handelt, haben Sie die Möglichkeit, die Abfrage in kleinere, einfachere Blöcke aufzuteilen und den Variablen im Verlaufe der Zeit Werte zuzuweisen. Dies kann einen großen Unterschied in der Lesbarkeit machen. Anstatt beispielsweise diese drei Unterabfragen zusammenzufassen oder zu gruppieren, können Sie im Voraus drei kleine eigenständige Abfragen ausführen, die den Variablen zusammengefasste Ergebnisse zuweisen, und dann einfach diese Variablen für Ihre Rückfrage auswählen. Potenziell viel einfacher zu lesen und zu verstehen und möglicherweise auch besser. –

Antwort

8

Ich würde die Abfrage auf folgende Weise ändern:

  1. die Aggregation in Subqueries tun. Dies kann weitere Informationen über die Tabelle zur Optimierung der group by nutzen.
  2. Kombinieren Sie die zweite und dritte Unterabfrage. Sie aggregieren in derselben Spalte. Dies erfordert die Verwendung eines left outer join, um sicherzustellen, dass alle Daten verfügbar sind.
  3. Mit count(<fieldname>) können Sie die Vergleiche zu is null beseitigen. Dies ist wichtig für den zweiten und dritten berechneten Wert.
  4. Um die zweite und dritte Abfrage zu kombinieren, muss eine ID aus der Tabelle mde gezählt werden. Diese verwenden mde.mdeid.

Die folgende Version folgt Ihr Beispiel durch union all mit:

SELECT CAST(Detail.ReceiptDate AS DATE) AS "Date", 
     SUM(TOTALMAILED) as TotalMailed, 
     SUM(TOTALUNDELINOTICESRECEIVED) as TOTALUNDELINOTICESRECEIVED, 
     SUM(TRACEUNDELNOTICESRECEIVED) as TRACEUNDELNOTICESRECEIVED 
FROM ((select SentDate AS "ReceiptDate", COUNT(*) as TotalMailed, 
       NULL as TOTALUNDELINOTICESRECEIVED, NULL as TRACEUNDELNOTICESRECEIVED 
     from MailDataExtract 
     where SentDate is not null 
     group by SentDate 
    ) union all 
     (select MDE.ReturnMailDate AS ReceiptDate, 0, 
       COUNT(distinct mde.mdeid) as TOTALUNDELINOTICESRECEIVED, 
       SUM(case when sd.ReturnMailTypeId = 1 then 1 else 0 end) as TRACEUNDELNOTICESRECEIVED 
     from MailDataExtract MDE left outer join 
      DTSharedData.dbo.ScanData SD 
      ON SD.ScanDataID = MDE.ReturnScanDataID 
     group by MDE.ReturnMailDate; 
    ) 
    ) detail 
GROUP BY CAST(Detail.ReceiptDate AS DATE) 
ORDER BY 1; 

Das folgende ist etwas ähnliches full outer join mit:

SELECT coalesce(sd.ReceiptDate, mde.ReceiptDate) AS "Date", 
     sd.TotalMailed, mde.TOTALUNDELINOTICESRECEIVED, 
     mde.TRACEUNDELNOTICESRECEIVED 
FROM (select cast(SentDate as date) AS "ReceiptDate", COUNT(*) as TotalMailed 
     from MailDataExtract 
     where SentDate is not null 
     group by cast(SentDate as date) 
    ) sd full outer join 
    (select cast(MDE.ReturnMailDate as date) AS ReceiptDate, 
      COUNT(distinct mde.mdeID) as TOTALUNDELINOTICESRECEIVED, 
      SUM(case when sd.ReturnMailTypeId = 1 then 1 else 0 end) as TRACEUNDELNOTICESRECEIVED 
    from MailDataExtract MDE left outer join 
      DTSharedData.dbo.ScanData SD 
      ON SD.ScanDataID = MDE.ReturnScanDataID 
    group by cast(MDE.ReturnMailDate as date) 
    ) mde 
    on sd.ReceiptDate = mde.ReceiptDate 
ORDER BY 1; 
0

Ich denke, Sie sollten eine Unterabfrage tun, um Gruppierung zu tun. In diesem Fall gibt die innere Unterabfrage nur wenige Zeilen zurück und Sie benötigen keine CASE-Anweisung. Also ich denke, das schneller sein wird:

select Detail.ReceiptDate AS 'DATE', 
     SUM(TotalMailed), 
     SUM(TotalReturnMail), 
     SUM(TraceReturnedMail) 

from 
(

select SentDate AS 'ReceiptDate', 
     count('TotalMailed') AS TotalMailed, 
     0 as TotalReturnMail, 
     0 as TraceReturnedMail 
from MailDataExtract 
where sentdate is not null 
GROUP BY SentDate 

UNION ALL 
select MDE.ReturnMailDate AS 'ReceiptDate', 
     0 AS TotalMailed, 
     count(TotalReturnMail) as TotalReturnMail, 
     0 as TraceReturnedMail 
from MailDataExtract MDE 
where MDE.ReturnMailDate is not null 
GROUP BY MDE.ReturnMailDate 

UNION ALL 

select MDE.ReturnMailDate AS 'ReceiptDate', 
     0 AS TotalMailed, 
     0 as TotalReturnMail, 
     count(TraceReturnedMail) as TraceReturnedMail 

from MailDataExtract MDE 
    inner join DTSharedData.dbo.ScanData SD 
     ON SD.ScanDataID = MDE.ReturnScanDataID 
    where MDE.ReturnMailDate is not null AND SD.ReturnMailTypeID = 1 
GROUP BY MDE.ReturnMailDate 

) as Detail 
GROUP BY Detail.ReceiptDate 
ORDER BY 1 
Verwandte Themen