使用PIVOT格式化多个SELECT语句

时间:2017-10-24 11:43:44

标签: sql sql-server tsql pivot unpivot

目前有一个脚本可以处理十几个SELECT语句,其中两个示例以及结果示例如下所示。

DECLARE @Age TABLE (name VARCHAR(30), total FLOAT, percentage FLOAT) 

INSERT INTO @Age
    SELECT '0-18', (SELECT COUNT(*) FROM tblPerson p
                INNER JOIN tblClient c ON c.intPersonID = p.intPersonID
                WHERE ISNULL(dbo.fncReportClient_Age(p.dteBirthdate, GETDATE()), '') >= 0 AND ISNULL(dbo.fncReportClient_Age(p.dteBirthdate, GETDATE()), '') <= 18), ''

UPDATE @Age
    SET percentage = ROUND((SELECT total FROM @Age WHERE name = '0-18')/(SELECT SUM(total) FROM @Age) * 100, 2)
    FROM @Age
    WHERE name = '0-18'
Etc.


SELECT 
    g.nvhGenderName, 
    COUNT(*),
        ROUND(COUNT(*) * 1.0 / SUM(COUNT(*)) OVER () * 100, 2)
FROM 
    tblClient c 
    LEFT JOIN tblPerson p ON p.intPersonID = c.intPersonID
    LEFT JOIN tblGender g ON g.intGenderID = p.intGenderID
GROUP BY g.nvhGenderName

UNION ALL 

SELECT * FROM @Age

以下结果示例:

Name    |   Total   |      %    |
---------------------------------
Male    |   6514    |   60.32   |
Female  |   4285    |   39.68   |
0-18    |   279     |   1.58    |
19-24   |   1748    |   9.93    |
25-34   |   5423    |   30.80   |
35-64   |   9546    |   54.21   |
65+     |   614     |   3.50    |

我希望水平显示这些结果而不是垂直显示,我认为可以用PIVOT做到这一点,但从未真正使用它们。我希望如何显示数据的示例如下所示:

Gender  |   Total   |   %   |   Age     |   Total   |   %   |   
-------------------------------------------------------------
Male    |   6514    | 60.32 |   0-18    |    279    | 1.58  |
Female  |   4285    | 39.68 |   19-24   |    1748   | 9.93  |
        |           |       |   25-34   |    5423   | 30.80 |
        |           |       |   35-64   |    9546   | 54.21 |
        |           |       |   65+     |    614    | 3.50  |                                

特别是我不确定如何使用数据透视表来组合需要它的多个(12)SELECT语句。

如何格式化这方面的任何帮助将非常感激。

2 个答案:

答案 0 :(得分:0)

虽然我认为布局确实应该在其他地方实现,但以下内容可能适合您。很明显我无法测试它,如果没有测试的好处,那么:

WITH myCTE AS (
      SELECT
            COUNT(CASE WHEN oa.age >= 0  AND oa.age < 19 THEN p.intPersonID ELSE NULL END) c0019
          , COUNT(CASE WHEN oa.age >= 19 AND oa.age < 25 THEN p.intPersonID ELSE NULL END) c1925
          , COUNT(CASE WHEN oa.age >= 25 AND oa.age < 35 THEN p.intPersonID ELSE NULL END) c2535
          , COUNT(CASE WHEN oa.age >= 35 AND oa.age < 65 THEN p.intPersonID ELSE NULL END) c3565
          , COUNT(CASE WHEN oa.age >= 65                 THEN p.intPersonID ELSE NULL END) c65on
          , COUNT(CASE WHEN g.nvhGenderName = 'Male'     THEN p.intPersonID ELSE NULL END) cmale
          , COUNT(CASE WHEN g.nvhGenderName = 'Female'   THEN p.intPersonID ELSE NULL END) cfemale
          , COUNT(*) ctotal
      FROM tblClient c
      LEFT JOIN tblPerson p ON p.intPersonID = c.intPersonID
      OUTER APPLY (
            SELECT
                  dbo.fncReportClient_Age(p.dteBirthdate) AS age
            ) AS oa
      LEFT JOIN tblGender g ON g.intGenderID = p.intGenderID
      )
SELECT
       ca.Gender, ca.Total2, ca.Pct, ca.Age, ca.Total2, ca.Pct2
FROM myCTE
CROSS APPLY (
         VALUES
           (1, 'Male' , t.cmale ,  (cmale * 100.0 / ctotal),  '0-18', c0019, (c0019 * 100.0 / ctotal))
         , (2, 'Female',t.cfemale,(cfemale * 100.0 / ctotal), '19-24', c1925, (c1925 * 100.0 / ctotal))
         , (3, NULL,NULL,NULL, '25-34', c2535, (c2535 * 100.0 / ctotal))
         , (4, NULL,NULL,NULL, '35-64', c3565, (c3565 * 100.0 / ctotal))
         , (5, NULL,NULL,NULL, '65+'  , c65on, (c65on * 100.0 / ctotal))
     ) AS ca (rn, Gender, Total2, Pct, Age, Total2, Pct2)
ORDER BY ca.rn
;    

上述查询的第二部分(较低部分)使用了unpivoting数据的技术,该技术将cross applyvalues结合在一起,这使我们能够布局&#34;想要的最终结果的每一行逐行。

使用CTE(上面的查询的上半部分)并不重要,可以将其移动到子查询中,但CTE内的查询应该先独立试验并且它应该在一次传递数据时生成所需的所有数字(假设性别表不会干扰计数结果)。请注意,使用count(case expression here)无需多个单独的查询。我怀疑你顺便不需要左连接,如果确实如此,你也可以将外部申请更改为交叉申请。请注意,apply用于执行您的函数,通过这样做,我们可以通过查询的其余部分中的别名引用该函数的结果(我使用&#34; age&#34;作为该别名)。

我不确定为什么在计算人员表时涉及客户表。我怀疑它不是必需的。如果我的怀疑是正确的,那么CTE细节可以被替换为:

  SELECT
        COUNT(CASE WHEN oa.age >= 0  AND oa.age < 19 THEN 1 ELSE NULL END) c0019
      , COUNT(CASE WHEN oa.age >= 19 AND oa.age < 25 THEN 1 ELSE NULL END) c1925
      , COUNT(CASE WHEN oa.age >= 25 AND oa.age < 35 THEN 1 ELSE NULL END) c2535
      , COUNT(CASE WHEN oa.age >= 35 AND oa.age < 65 THEN 1 ELSE NULL END) c3565
      , COUNT(CASE WHEN oa.age >= 65                 THEN 1 ELSE NULL END) c65on
      , COUNT(CASE WHEN g.nvhGenderName = 'Male'     THEN 1 ELSE NULL END) cmale
      , COUNT(CASE WHEN g.nvhGenderName = 'Feale'    THEN 1 ELSE NULL END) cfemale
      , COUNT(*) ctotal
  FROM tblPerson p
  CROSS APPLY (
        SELECT
              dbo.fncReportClient_Age(p.dteBirthdate) AS age
        ) AS oa
  INNER JOIN tblGender g ON g.intGenderID = p.intGenderID

答案 1 :(得分:-1)

Create VIEW view_name AS

SELECT * FROM (
  select ColumnName1,ColumnName2 from TableName
) as s
PIVOT (
Sum(ColumnName2)
  FOR ColumnName3 in ("Row1","Row2","Row3"
  )
) As pvt


DROP VIEW view_name;


Select * from view_name