如何使用PIVOT简化或现代化此SQL语句?

时间:2017-04-27 14:31:30

标签: sql-server tsql pivot

下面我有一个SQL语句(实际上是动态生成的),我创建了5列。第一个是客户名称,第二个,第三个和第四个是每个月的记录数,第五个是最近一个月和上个月之间的差异。

SELECT ClientName AS 'Reporting',  
    (SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate='20170101') 
  AS '20170101', 
    (SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate='20170201') 
  AS '20170201', 
    (SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate='20170301') 
  AS '20170301', 
       (SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate='20170301')
      -(SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate='20170201') 
  AS 'Difference' 

from FRU -- Removed: left outer join UMP on FRU.UnitID=UMP.UnitID 
  group by FRU.ClientName, FRU.ClientID 
  order by ClientName

这似乎是练习我的PIVOT技能的好时机,但我没有。 你能转换成PIVOT使我可以向你学习吗?

对于增加的惊奇值,这是我用来生成上述语句的实际SQL。如果你能转换这个,我将欠你一个含糊不清的无法识别的物品或服务。

我使用@coreSQL,因为我对@qry稍作修改后再多次使用该部分。

    DECLARE @qry nvarchar(max)

  --In modern SQL I use format(DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-2, 0),'yyyyMMdd')
  --In crappy old 2008 SQL:
  DECLARE @OneMonth varchar(8) = replace(convert(varchar, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0), 111), '/', '')
  DECLARE @TwoMonths varchar(8) = replace(convert(varchar, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-2, 0), 111), '/', '')
  DECLARE @ThreeMonths varchar(8) = replace(convert(varchar, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-3, 0), 111), '/', '')
  DECLARE @coreSQL varchar(max)

  SET @coreSQL = ' (SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate=''' + @ThreeMonths + ''') AS ''' + @ThreeMonths + ''','
  SET @coreSQL = @coreSQL + ' (SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate=''' + @TwoMonths + ''') AS ''' + @TwoMonths + ''','
  SET @coreSQL = @coreSQL + ' (SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate=''' + @OneMonth + ''') AS ''' + @OneMonth + ''','
  SET @coreSQL = @coreSQL + ' (SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate=''' + @OneMonth + ''')-(SELECT count(UMP.INDX) from UMP where ClientID=FRU.ClientID and LogActivityDate=''' + @TwoMonths + ''') AS ''Difference'''

  -- Raw results
  SET @qry = 'SELECT ClientName AS ''Reporting'', '
  SET @qry = @qry+@coreSQL
  SET @qry = @qry + ' from FRU group by FRU.ClientName, FRU.ClientID order by ClientName'

  EXECUTE sp_Executesql @qry

3 个答案:

答案 0 :(得分:1)

不需要PIVO:

SELECT
  ClientName AS 'Reporting',  
  SUM(CASE WHEN UMP.LogActivityDate='20170101' THEN 1 ELSE 0 END) AS '20170101', 
  SUM(CASE WHEN UMP.LogActivityDate='20170102' THEN 1 ELSE 0 END) AS '20170102', 
  SUM(CASE WHEN UMP.LogActivityDate='20170103' THEN 1 ELSE 0 END) AS '20170103', 
  SUM(CASE WHEN UMP.LogActivityDate='20170103' THEN 1 WHEN UMP.LogActivityDate='20170103' THEN -1 ELSE 0 END) AS 'Difference', 
  from FRU
  left outer join UMP on (FRU.UnitID=UMP.UnitID AND ClientID=FRU.ClientID)
  group by FRU.ClientName, FRU.ClientID 
  order by ClientName

希望它会帮助你......

答案 1 :(得分:1)

SELECT
  ClientName,
  [20170101], [20170201], [20170301], [20170301] - [20170201] AS 'Difference'
FROM
  (
    SELECT FRU.ClientName, UMP.LogActivityDate, COUNT(1) AS Counted
    FROM FRU
    FULL JOIN UMP
      ON FRU.UnitID = UMP.UnitID AND
         FRU.ClientID = UMP.ClientID
    GROUP BY
      ClientName, LogActivityDate
  ) AS SourceTable
PIVOT
  (
    SUM(Counted)
    FOR LogActivityDate IN ([20170101], [20170201], [20170301])
  ) AS PivotTable

答案 2 :(得分:0)

您的外部查询仅获取客户端名称。与UMP的加入似乎完全是多余的。

顺便说一句,我看不出PIVOT如何在这里提供帮助。我使用条件聚合:

select 
  fru.clientname as "Reporting",
  coalesce(u.cnt20170101, 0) as "20170101",
  coalesce(u.cnt20170201, 0) as "20170201",
  coalesce(u.cnt20170301, 0) as "20170301",
  coalesce(u.cnt20170301, 0) - coalesce(u.cnt20170201, 0) as "difference"
from fru
left join
(
  select
    clientid, 
    count(case when logactivitydate = '20170101' then 1 end) as cnt20170101,
    count(case when logactivitydate = '20170201' then 1 end) as cnt20170201,
    count(case when logactivitydate = '20170301' then 1 end) as cnt20170301
  from ump
  group by clientid
) u on u.clientid = fru.clientid;

BTW:单引号用于字符串文字,双引号用于别名。 (但由于这是SQL Server,您可能必须使用非标准括号替换它们,例如as [Reporting]