2013-07-23 25 views
11

Tôi đang tìm cách xem có cách tiếp cận nào tốt hơn cho truy vấn bên dưới không. Những gì tôi đang cố gắng làm là tạo một báo cáo tóm tắt, biên soạn số liệu thống kê theo ngày.Truy vấn SQL - SUM (TRƯỜNG HỢP KHI x THÌ 1 ELSE 0) cho nhiều cột

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 

Đây chỉ là một mẫu truy vấn (được sử dụng trong báo cáo) vì có một số cột khác và logic cho các thống kê khác phức tạp hơn. Có cách tiếp cận trang nhã hơn để nhận loại thông tin/viết loại báo cáo này không?

+0

Đây có phải là trong một proc hoặc một cái nhìn, hay cái gì khác? Về cơ bản, bạn có thể giới thiệu các biến và chạy nhiều câu lệnh hay chỉ là một câu lệnh 'select' lớn? –

+0

Đó là một proc sẽ được sử dụng cho một báo cáo SSRS, do đó, nó sẽ cần phải về cơ bản là một tuyên bố chọn như tôi cần phải trả lại một tập kết quả (phải không?) – MickJuice

+0

Vâng, cuối cùng bạn sẽ có một 'lựa chọn 'lớn tại kết thúc, nhưng vì nó nằm trong proc, bạn sẽ có khả năng chia truy vấn của mình thành các phần nhỏ hơn, đơn giản hơn, gán các giá trị cho các biến khi bạn đi theo. Điều này có thể tạo ra sự khác biệt lớn về khả năng đọc. Ví dụ, thay vì 'union'ing hoặc nhóm ba truy vấn phụ này, bạn có thể có ba truy vấn độc lập nhỏ chạy trước, gán kết quả tóm tắt cho biến, sau đó chỉ cần chọn các biến đó cho truy vấn trả về của bạn. Có khả năng đọc và hiểu dễ dàng hơn nhiều và có thể hoạt động tốt hơn. –

Trả lời

8

tôi sẽ thay đổi truy vấn trong các cách sau:

  1. Làm hợp trong truy vấn con. Điều này có thể tận dụng thêm thông tin về bảng để tối ưu hóa group by.
  2. Kết hợp các truy vấn phụ thứ hai và thứ ba. Chúng được tổng hợp trên cùng một cột. Điều này yêu cầu sử dụng left outer join để đảm bảo rằng tất cả dữ liệu có sẵn.
  3. Bằng cách sử dụng count(<fieldname>) bạn có thể loại bỏ các so sánh với is null. Điều này quan trọng đối với các giá trị được tính toán thứ hai và thứ ba.
  4. Để kết hợp các truy vấn thứ hai và thứ ba, nó cần phải tính một id từ bảng mde. Chúng sử dụng mde.mdeid.

Phiên bản sau sau ví dụ của bạn bằng cách sử dụng union all:

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; 

Sau đây không một cái gì đó tương tự như sử dụng full outer join:

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

Tôi nghĩ bạn nên tạo một truy vấn phụ để nhóm. Trong trường hợp này, truy vấn phụ bên trong trả về một vài hàng và bạn không cần một câu lệnh CASE. Vì vậy, tôi nghĩ rằng đây sẽ là nhanh hơn:

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 
Các vấn đề liên quan