2013-06-17 62 views
9

Tôi có một bảng với các cột sauSử dụng bảng pivot với tổng số cột và hàng trong sql server 2008

defect_id, developer_name, status, summary, root_cause, 
Secondary_RC, description, Comments, environment_name 

Cột root_cause có Enviro, requi, Dev, TSC, TD, Unkn như các giá trị và của cột environment_name có QA1, QA2, QA3

tôi cần phải chuẩn bị một báo cáo trong định dạng dưới đây

Enviro Requi Dev TSc TD Unkn Total 
QA1 9 1  14 17 2 3 46 
QA2 8 1  14 0 5 1 29 
QA3 1 1  7 0 0 1 10 
Total 18 3  35 17 7 5 85 

tôi có chuẩn bị báo cáo đến

Enviro Requi Dev TSc TD Unkn 
QA1 9 1  14 17 2 3 
QA2 8 1  14 0 5 1 
QA3 1 1  7 0 0 1 

tôi đã sử dụng các truy vấn dưới đây để có được những kết quả trên

select * 
from 
(
    select environment_name as " ", value 
    from test1 
    unpivot 
    (
    value 
    for col in (root_cause) 
) unp 
) src 
pivot 
(
    count(value) 
    for value in ([Enviro] , [Requi] , [Dev] , [Tsc], [TD] , [Unkn]) 
) piv 

thể bất cứ ai giúp đỡ để có được tổng số cho các cột và các hàng?

+0

Chào mừng bạn đến với StackOverflow: nếu bạn đăng mã, XML hoặc mẫu dữ liệu, hãy ** tô sáng những dòng đó trong trình soạn thảo văn bản và nhấp vào nút "mẫu mã" ('{}') trên thanh công cụ của trình soạn thảo để định dạng độc đáo và cú pháp làm nổi bật nó! –

+0

Mục đích của phần 'unpivot' trong truy vấn này là gì? Chắc chắn, bạn có thể thay thế toàn bộ truy vấn phụ chỉ bằng 'select environment_name as" ", root_cause làm giá trị từ test1', không? –

+0

Xin lỗi, tôi có nghĩa là bạn có thể * viết lại * như thế. –

Trả lời

15

Có thể có nhiều cách tiếp cận khác nhau. Bạn có thể tính toán tất cả các tổng số sau trục, hoặc bạn có thể nhận được tổng số đầu tiên, sau đó xoay vòng tất cả các kết quả. Cũng có thể có loại nền tảng trung bình: có được một loại tổng số (ví dụ như các loại hàng ngang), trục xoay, sau đó lấy loại khác, mặc dù điều đó có thể làm quá mức.

Việc đầu tiên của các phương pháp đã đề cập, nhận được tất cả những tổng số sau khi trục, có thể được thực hiện theo một cách rất đơn giản, và điều duy nhất có khả năng mới cho bạn trong việc thực hiện dưới đây có thể là GROUP BY ROLLUP():

SELECT 
    [ ]  = ISNULL(environment_name, 'Total'), 
    [Enviro] = SUM([Enviro]), 
    [Requi] = SUM([Requi]), 
    [Dev] = SUM([Dev]), 
    [Tsc] = SUM([Tsc]), 
    [TD]  = SUM([TD]), 
    [Unkn] = SUM([Unkn]), 
    Total = SUM([Enviro] + [Requi] + [Dev] + [Tsc] + [TD] + [Unkn]) 
FROM (
    SELECT environment_name, root_cause 
    FROM test1 
) s 
PIVOT (
    COUNT(root_cause) 
    FOR root_cause IN ([Enviro], [Requi], [Dev], [Tsc], [TD], [Unkn]) 
) p 
GROUP BY 
    ROLLUP(environment_name) 
; 

Về cơ bản, phần GROUP BY ROLLUP() tạo ra tổng số hàng cho bạn. Việc nhóm đầu tiên được thực hiện bởi environment_name, sau đó hàng tổng cộng lớn được thêm vào.

Để làm điều ngược lại, tức là lấy tổng số trước pivoting, bạn có thể sử dụng GROUP BY CUBE() như thế này:

SELECT 
    [ ]  = environment_name, 
    [Enviro] = ISNULL([Enviro], 0), 
    [Requi] = ISNULL([Requi] , 0), 
    [Dev] = ISNULL([Dev] , 0), 
    [Tsc] = ISNULL([Tsc] , 0), 
    [TD]  = ISNULL([TD] , 0), 
    [Unkn] = ISNULL([Unkn] , 0), 
    Total = ISNULL(Total , 0) 
FROM (
    SELECT 
    environment_name = ISNULL(environment_name, 'Total'), 
    root_cause  = ISNULL(root_cause,  'Total'), 
    cnt    = COUNT(*) 
    FROM test1 
    WHERE root_cause IS NOT NULL 
    GROUP BY 
    CUBE(environment_name, root_cause) 
) s 
PIVOT (
    SUM(cnt) 
    FOR root_cause IN ([Enviro], [Requi], [Dev], [Tsc], [TD], [Unkn], Total) 
) p 
; 

Cả hai phương pháp có thể được kiểm tra và chơi với ít SQL Fiddle:

Lưu ý. Tôi đã bỏ qua bước bỏ phiếu trong cả hai đề xuất vì việc bỏ cấm một cột đơn có vẻ rõ ràng là dư thừa. Tuy nhiên, nếu có nhiều điều hơn, việc điều chỉnh một trong các truy vấn phải dễ dàng.

+0

Cảm ơn rất nhiều, Got nó ở định dạng chính xác là tốt. – user1931944

+0

Bổ sung nhỏ cho Phương pháp 1 và MSSQL 2005 (có, nó vẫn được sử dụng ở đâu đó ..) Sql2005 nói rằng không có hàm ROLLUP như vậy, giải pháp là thay thế "GROUP BY ROLLUP (environment_name)" bằng "GROUP BY environment_name WITH ROLLUP "cũng hoạt động với Sql2008. Cũng không rõ tại sao có truy vấn phụ trong FROM - thay vì "FROM (..) s" có thể chỉ là "FROM test1". Trong mọi trường hợp +1, rất hữu ích! – sarh

+0

@ sarh: Re: tại sao subquery - nếu nó đơn giản là 'FROM test1 PIVOT ...', thì PIVOT sẽ sử dụng tất cả các cột trong 'test1' (ngoài một cột được chỉ định làm đối số của hàm tổng hợp) làm tiêu chí nhóm, nhưng chúng ta chỉ cần nhóm theo 'environment_name'. –

1

Tôi nghĩ bạn cần tính tổng riêng. Sử dụng truy vấn đơn giản này cho tổng số (xin lỗi, đã để cho tên bí danh cho "" cột của bạn):

select environment_name as en, 
count (*) AS Total 
FROM test1 
WHERE value in ('Enviro', 'Requi', 'Dev', 'Tsc', 'TD', 'Unkn') 
GROUP BY environment_name 

bạn có thể dễ dàng tham gia cả hai truy vấn với nhau để có được báo cáo yêu cầu:

SELECT * FROM 
(select * 
from 
(
    select environment_name as en, value 
    from test1 
    unpivot 
    (
    value 
    for col in (root_cause) 
) unp 
) src 
pivot 
(
    count(value) 
    for value in ([Enviro] , [Requi] , [Dev] , [Tsc], [TD] , [Unkn]) 
) piv 
) AS a 
INNER JOIN 
(select environment_name as en, 
    count (*) AS Total 
    FROM test1 
    WHERE value in ('Enviro', 'Requi', 'Dev', 'Tsc', 'TD', 'Unkn') 
    GROUP BY environment_name 
) AS b ON a.en = b.en 
UNION ALL 
SELECT * FROM 
(select * 
from 
(
    select 'Total' as en, value 
    from test1 
    unpivot 
    (
    value 
    for col in (root_cause) 
) unp 
) src 
pivot 
(
    count(value) 
    for value in ([Enviro] , [Requi] , [Dev] , [Tsc], [TD] , [Unkn]) 
) piv 
) AS a 
INNER JOIN 
(select 'Total' as en, 
    count (*) AS Total 
    FROM test1 
    WHERE value in ('Enviro', 'Requi', 'Dev', 'Tsc', 'TD', 'Unkn') 
) AS b 

Tôi chưa thử nghiệm, nhưng tin rằng nó sẽ hoạt động

+0

Cảm ơn cha, nó đã làm việc cho tổng số hàng. Vẫn còn Iam cố gắng cho các cột tổng số – user1931944

+0

bạn có ý nghĩa gì? nó có tính toán đúng không? – cha

+0

Nó chỉ tính toán tổng số hàng khôn ngoan một mình nhưng tôi cần tổng số cột khôn ngoan như wel Cha. – user1931944

2

Bạn có thể tìm Tổng số cho root_causeenvironment_name sử dụng ROLLUP.

  • RNO_COLTOTAL - Logic để đặt Total ở cột cuối cùng, vì các cột Tsc, Unkn sẽ chồng lên cột Total khi xoay vòng, kể từ khi đặt hàng của mình theo thứ tự abc.
  • RNO_ROWTOTAL - Logic để đặt Total ở hàng cuối cùng từ một giá trị được bắt đầu với U, W, X, Y, Z có thể chồng lên giá trị Total, kể từ khi đặt hàng của mình theo thứ tự abc.
  • SUM(VALUE) - Có thể xác định chức năng tổng hợp nào chúng tôi có thể sử dụng với ROLLUP.

QUERY 1

SELECT CASE WHEN root_cause IS NULL THEN 1 ELSE 0 END RNO_COLTOTAL, 
CASE WHEN environment_name IS NULL THEN 1 ELSE 0 END RNO_ROWTOTAL, 
ISNULL(environment_name,'Total')environment_name, 
ISNULL(root_cause,'Total')root_cause, 
SUM(VALUE) VALUE 
INTO #NEWTABLE 
FROM 
(
    -- Find the count for environment_name,root_cause 
    SELECT DISTINCT *,COUNT(*) OVER(PARTITION BY environment_name,root_cause)VALUE 
    FROM #TEMP 
)TAB 
GROUP BY root_cause,environment_name 
WITH CUBE 

Chúng tôi sẽ nhận được logic sau khi CUBE được sử dụng

enter image description here

Chúng tôi khai báo các biến cho pivoting.

  • @cols - Giá trị cột cho xoay vòng.
  • @NulltoZeroCols - Thay thế giá trị null bằng 0.

QUERY 2

DECLARE @cols NVARCHAR (MAX) 

SELECT @cols = COALESCE (@cols + ',[' + root_cause + ']', 
       '[' + root_cause + ']') 
       FROM (SELECT DISTINCT RNO_COLTOTAL,root_cause FROM #NEWTABLE) PV 
       ORDER BY RNO_COLTOTAL,root_cause 

DECLARE @NulltoZeroCols NVARCHAR (MAX) 

SET @NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+root_cause+'],0) AS ['+root_cause+']' 
FROM(SELECT DISTINCT RNO_COLTOTAL,root_cause FROM #NEWTABLE GROUP BY RNO_COLTOTAL,root_cause)TAB 
ORDER BY RNO_COLTOTAL FOR XML PATH('')),2,8000) 

Bây giờ xoay nó tự động

DECLARE @query NVARCHAR(MAX) 
SET @query = 'SELECT environment_name,'+ @NulltoZeroCols +' FROM 
      (
       SELECT RNO_ROWTOTAL,environment_name,root_cause,VALUE 
       FROM #NEWTABLE 
      ) x 
      PIVOT 
      (
       MIN(VALUE) 
       FOR [root_cause] IN (' + @cols + ') 
      ) p 
      ORDER BY RNO_ROWTOTAL,environment_name;' 

EXEC SP_EXECUTESQL @query 

KẾT QUẢ

enter image description here