2009-07-23 38 views
9

Tương tự như this question, tôi cần nhóm một số lượng lớn các bản ghi thành các nhóm "1 giờ". Ví dụ, giả sử tôi có một bảng ORDER điển hình với một datetime được đính kèm theo mỗi thứ tự. Và tôi muốn xem tổng số đơn hàng mỗi giờ. Vì vậy, tôi đang sử dụng SQL gần như thế này:Việc nhóm/tập hợp kết quả SQL vào các nhóm 1 giờ

SELECT datepart(hh, order_date), SUM(order_id) 
FROM ORDERS 
GROUP BY datepart(hh, order_date) 

Vấn đề là nếu không có đơn đặt hàng trong một "xô" 1 giờ nhất định, không có hàng nào được phát ra trong tập hợp kết quả. Tôi muốn resultset có một hàng cho mỗi 24 giờ, nhưng nếu không có đơn đặt hàng được thực hiện trong một giờ cụ thể, chỉ cần ghi lại số lượng đơn đặt hàng là O.

Có cách nào để thực hiện điều này trong một truy vấn đơn lẻ?

Xem thêm Getting Hourly Statistics Using SQL.

+0

Nó sẽ giúp biết bạn đang sử dụng phiên bản Pg nào. –

Trả lời

7

Bạn cần có bảng được điền trước (hoặc một hàm trả về tập kết quả bảng) để tham gia, có chứa tất cả các vị trí trong 1 giờ bạn muốn trong kết quả của mình.

Sau đó, bạn thực hiện một OUTER JOIN với điều đó và bạn sẽ nhận được tất cả.

Something như thế này:

SELECT SLOT_HOUR, SUM(order_id) 
FROM 
    ONEHOURSLOTS 
    LEFT JOIN ORDERS ON DATEPART(hh, order_date) = SLOT_HOUR 
GROUP BY SLOT_HOUR 
+0

Tôi tin rằng bạn cũng có thể thay thế 'ONEHOURSLOTS' bằng một cái gì đó như '(chọn 0 là SLOT_HOUR union chọn 1 là SLOT_HOUR union ..)' - chỉ khi bạn đã chết đặt nó trong một truy vấn mặc dù - yuck: P – Blorgbeard

+0

Bạn có thể làm điều đó ngay cả người dùng dễ dàng hơn generate_series() (giả sử bạn đang ở trên postgres, mà các thẻ nói rằng bạn đang có, nhưng truy vấn ví dụ sẽ không hoạt động ở đó ..) –

2

Tạo một bảng giờ, hoặc là vẫn kiên trì hoặc thậm chí tổng hợp 'trên bay':

SELECT h.hour, s.sum 
FROM (
    SELECT 1 as hour 
    UNION ALL SELECT 2 
    UNION ALL SELECT 3 
    ... 
    UNION ALL SELECT 24) as h 
LEFT OUTER JOIN (
    SELECT datepart(hh, order_date) as hour, SUM(order_id) as sum 
     FROM ORDERS 
     GROUP BY datepart(hh, order_date)) as s 
    ON h.hour = s.hour; 
8

Một số các câu trả lời trước đó khuyên bạn nên sử dụng một bảng giờ và điền nó bằng truy vấn UNION; điều này có thể được thực hiện tốt hơn với Biểu thức bảng chung:

; WITH [Hours] ([Hour]) AS 
(
SELECT TOP 24 ROW_NUMBER() OVER (ORDER BY [object_id]) AS [Hour] 
FROM sys.objects 
ORDER BY [object_id] 
) 
SELECT h.[Hour], o.[Sum] 
FROM [Hours] h 
LEFT OUTER JOIN (
    SELECT datepart(hh, order_date) as [Hour], SUM(order_id) as [Sum] 
     FROM Orders 
     GROUP BY datepart(hh, order_date) 
) o 
ON h.[Hour] = o.[Hour] 
+0

+1 cho thủ thuật sys.objects. Một ngày nào đó họ sẽ phát hành một phiên bản chỉ hiển thị các đối tượng người dùng có quyền truy cập vào sys.object và di chuyển các đối tượng hệ thống vào sys.all_objects, để hủy hoại kịch bản của bạn lol –

+0

Hy vọng rằng, đó sẽ là phiên bản có bảng số (http : //sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html) trong đó, vì vậy bạn sẽ không cần hack như thế này –

Các vấn đề liên quan