2012-05-10 31 views
7

Tôi đang cố gắng tinh chỉnh truy vấn SQL để làm cho báo cáo của mình trông đẹp hơn. Truy vấn của tôi đọc dữ liệu từ một bảng, nhóm theo một vài colums và tính toán một số trường tổng hợp (số lượng và tổng).Cách tạo kết quả tổng hợp "trống" trong SQL

SELECT A, B, C, COUNT(*), SUM(D) FROM T 
GROUP BY A, B, C 
ORDER BY A, B, C 

Bây giờ, chúng ta hãy giả định cột B và C là một số các hằng xâu được định nghĩa, ví dụ, B có thể 'B1' hoặc 'B2', C có thể 'C1' hoặc 'C2'. Vì vậy, một ví dụ resultset là:

A | B | C | COUNT(*) | SUM(D) 
-------------------------------- 
A1 | B1 | C1 |  34 | 1752 
A1 | B1 | C2 |  4 | 183 
A1 | B2 | C1 |  199 | 8926 
A1 | B2 | C2 |  56 | 2511 
A2 | B1 | C2 |  6 |  89 
A2 | B2 | C2 |  12 | 231 
A3 | B1 | C1 |  89 | 552 
... 

Như bạn có thể thấy, cho 'A1' Tôi có tất cả kết hợp Bốn thể (B, C), nhưng đó là không đúng sự thật cho 'A2'. Câu hỏi của tôi là: làm thế nào tôi có thể tạo ra các hàng tóm tắt cho sự kết hợp (B, C) không hiện diện, trên thực tế, trong bảng đã cho? Đó là, làm thế nào tôi có thể in, ví dụ, cũng những hàng:

A | B | C | COUNT(*) | SUM(D) 
-------------------------------- 
A2 | B1 | C1 |  0 |  0 
A2 | B2 | C1 |  0 |  0 

Giải pháp duy nhất tôi có thể thấy là để tạo ra một số bảng auxiliarity với tất cả (B, C) giá trị và sau đó tạo ra một RIGHT OUTER JOIN với bảng aux đó. Nhưng tôi đang tìm kiếm một cách rõ ràng hơn ...

Cảm ơn tất cả.

+0

Bạn đang sử dụng mssql, oracel, mysql? – Arion

+0

Oracle. Nhưng truy vấn được viết, vào lúc này, theo một cách tiêu chuẩn (nó cũng chạy trên MySQL, chúng ta có một bản sao MySQL của DB không có lý do liên quan đến câu hỏi). –

+0

Có thể [this] (http://www.techrepublic.com/article/group-by-grouping-sets-for-custom-rollups-in-oracle/6134424) giúp. Các bộ nhóm có sẵn trong cả SQL Server và Oracle. Không chắc về MySQL. –

Trả lời

2

Bảng phụ không phải là bảng thực, nó có thể là biểu thức bảng chung - ít nhất là nếu bạn có thể nhận được tất cả các giá trị có thể (hoặc tất cả những gì bạn quan tâm) từ chính bảng đó. Sử dụng truy vấn @ Bob Jarvis' để tạo ra tất cả các kết hợp có thể bạn có thể làm một cái gì đó như:

WITH CTE AS (
    SELECT * FROM (SELECT DISTINCT a FROM T) 
    JOIN (SELECT DISTINCT b, c FROM T) ON (1 = 1) 
) 
SELECT CTE.A, CTE.B, CTE.C, 
    SUM(CASE WHEN T.A IS NULL THEN 0 ELSE 1 END), NVL(SUM(T.D),0) 
FROM CTE 
LEFT JOIN T ON T.A = CTE.A AND T.B = CTE.B AND T.C = CTE.C 
GROUP BY CTE.A, CTE.B, CTE.C 
ORDER BY CTE.A, CTE.B, CTE.C; 

Nếu bạn đã cố định giá trị mà có thể không trong bảng sau đó nó phức tạp (hoặc xấu xí hơn một chút dù sao, và sẽ tồi tệ hơn với giá trị hơn càng tốt):

WITH CTE AS (
    SELECT * FROM (SELECT DISTINCT a FROM T) 
    JOIN (SELECT 'B1' AS B FROM DUAL 
     UNION ALL SELECT 'B2' FROM DUAL) ON (1 = 1) 
    JOIN (SELECT 'C1' AS C FROM DUAL 
     UNION ALL SELECT 'C2' FROM DUAL) ON (1 = 1) 
) 
SELECT CTE.A, CTE.B, CTE.C, 
    SUM(CASE WHEN T.A IS NULL THEN 0 ELSE 1 END), NVL(SUM(T.D),0) 
FROM CTE 
LEFT JOIN T ON T.A = CTE.A AND T.B = CTE.B AND T.C = CTE.C 
GROUP BY CTE.A, CTE.B, CTE.C 
ORDER BY CTE.A, CTE.B, CTE.C; 

Nhưng bạn phải tham gia vào một cái gì đó mà biết về sự 'mất tích' giá trị. Nếu cùng một logic là cần thiết ở nơi khác, và bạn có giá trị cố định, sau đó một bảng vĩnh viễn có thể được sạch hơn - bảo trì có thể cần thiết hoặc là cách tất nhiên. Bạn cũng có thể xem xét một hàm pipelined để hoạt động như một bảng thay thế, nhưng phụ thuộc vào khối lượng có thể.

+1

Bản thân bảng chứa tất cả các khả năng. Rõ ràng, tôi đã không hy vọng động cơ DB sẽ "đoán" chúng. 1 cho việc sử dụng thú vị của 'WITH', tôi chưa bao giờ thấy t trước đây. –

1

Vấn đề là, nếu bạn không có kết hợp cụ thể trong cơ sở dữ liệu của mình, làm cách nào một công cụ biết để bao gồm kết hợp đó vào kết quả? Để có tất cả các kết hợp trong kết quả, bạn cần phải có tất cả các kết hợp có sẵn - cho dù trong bảng chính hoặc trong một số bảng khác được sử dụng để tham chiếu. Ví dụ, bạn có thể tạo ra một bảng R với dữ liệu như vậy:

A | B | C 
------------ 
A1 | B1 | C1 
A1 | B1 | C2 
A1 | B2 | C1 
A1 | B2 | C2 
A2 | B1 | C1 
A2 | B1 | C2 
A2 | B2 | C1 
A2 | B2 | C2 
A3 | B1 | C1 
A3 | B1 | C2 
A3 | B1 | C1 
A3 | B2 | C2 
... 

Và sau đó truy vấn của bạn sẽ trông như thế này:

SELECT r.*, COUNT(t.d), coalesce(SUM(t.d), 0) 
FROM r LEFT OUTER JOIN t on (r.a=t.a and r.b=t.b and r.c=t.c) 
GROUP BY r.a, r.b, r.c 
ORDER BY r.a, r.b, r.c 

này sẽ trả lại cho bạn những bộ như bạn muốn với 0 | 0 cho kết hợp không tồn tại trong bảng chính. Lưu ý rằng điều này chỉ có thể xảy ra nếu bạn biết mọi kết hợp có thể bạn muốn đưa vào, điều này có thể không phải lúc nào cũng đúng.

Nếu mặt khác Một bạn, B, C là các giá trị số và bạn chỉ muốn bao gồm tất cả các số trong một dãy, sau đó có thể có một cách khác để đối phó với điều này, một cái gì đó như thế này:

SELECT a.n, b.n, c.n, COUNT(t.d), coalesce(SUM(t.d), 0) 
FROM (SELECT (rownum) "n" FROM DUAL WHERE LEVEL >= start_a CONNECT BY LEVEL <= end_a) a, 
    (SELECT (rownum) "n" FROM DUAL WHERE LEVEL >= start_b CONNECT BY LEVEL <= end_b) b, 
    (SELECT (rownum) "n" FROM DUAL WHERE LEVEL >= start_c CONNECT BY LEVEL <= end_c) c, 
    t 
WHERE a.n = t.a(+) AND b.n = t.b(+) AND c.n = t.c(+) 
GROUP BY a.n, b.n, c.n 
ORDER BY a.n, b.n, c.n 

(Tôi không có một phiên bản Oracle tiện dụng để kiểm tra điều này, do đó, đây là nhiều hơn một dự đoán có phần giáo dục hơn là bất cứ điều gì khác.)

Dòng dưới cùng là động cơ cần biết những gì để đưa vào kết quả - theo cách này hay cách khác.

+0

Đó là cách tôi đang làm ngay bây giờ. Xem đoạn cuối cùng trong câu hỏi của tôi. –

+0

@ lorenzo-s Vấn đề chính là nếu không có bạn chỉ định tất cả các kết hợp hợp lệ, động cơ không có cách nào để biết, do đó bạn cần phải có bảng tạm thời này. –

+0

Bản thân bảng (xem xét tất cả các hàng) chứa tất cả các kết hợp của các giá trị (B, C). –

0

Có cách có thể đẹp hơn để làm điều này, nhưng sau đây sẽ giúp bạn bắt đầu hướng tới những gì bạn muốn:

SELECT * FROM 
    (SELECT DISTINCT a FROM T) 
JOIN 
    (SELECT DISTINCT b, c FROM T) 
    ON (1 = 1) 
ORDER BY a, b, c 

này sẽ cung cấp cho bạn tất cả các kết hợp mà tồn tại của B và C, cùng với tất cả của A có tồn tại , tương tự như

A1 B1 C1 
A1 B1 C2 
A1 B2 C1 
A1 B2 C2 
A2 B1 C1 
A2 B1 C2 
A2 B2 C1 
A2 B2 C2 

Chia sẻ và thưởng thức.

+0

Tôi đang tìm kiếm một thứ gì đó (và tôi không giả định rằng nó đã được xuất bản!) Không liên quan đến việc tham gia hay như vậy ... Tôi hiện đang sử dụng một bảng như bảng bạn đã viết để đạt được kết quả. Xem đoạn cuối cùng trong câu hỏi của tôi. –

+0

Vấn đề ở đây khác. Nếu bảng T chứa tất cả các kết hợp có thể, thì bạn ổn, tuy nhiên nó không có, sau đó bạn trở lại hình vuông. Bằng cách nào đó công cụ DB cần phải biết tất cả các kết hợp có thể là gì. –

+0

@AleksG Ok, ok, chúng tôi không có vấn đề này: bản thân bảng (xem xét tất cả các hàng) chứa tất cả các kết hợp (B, C) giá trị. Rõ ràng, tôi đã không hy vọng động cơ DB sẽ "đoán" chúng. –

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