当有 'Totals' 列时如何使用 Pivot?

How do I use Pivot when there's a 'Totals' column?

我整理了一个查询,显示 wells/year 的数量并在名为“总计”的列中汇总它们的总数。请参阅工作查询 post 底部的 db<>fiddle link。

SELECT
    YEAR(wd.eventdate) AS [Year],
    ISNULL(COUNT(DISTINCT w_oil.WellID), 0) AS [Oil Wells],
    ISNULL(COUNT(DISTINCT w_gas.WellID), 0) AS [Gas Wells],
    ISNULL(COUNT(DISTINCT w_service.WellID), 0) AS [Service Wells],
    ISNULL(COUNT(DISTINCT w_dry.WellID), 0) AS [Dry Holes],
    ISNULL(COUNT(DISTINCT w_tot.WellID), 0) AS [Totals]
FROM HWellDate wd
    LEFT JOIN HWell w_oil ON (w_oil.PKey = wd.WellKey and w_oil.WellType = 'OW')
    LEFT JOIN HWell w_gas ON (w_gas.PKey = wd.WellKey and w_gas.WellType = 'GW')
    LEFT JOIN HWell w_service ON
    (
    w_service.PKey = wd.WellKey
    AND w_service.WellType IN ('WI','GI','GS','WD','WS','TW')
    )
    LEFT JOIN HWell w_dry ON (w_dry.PKey = wd.WellKey and w_dry.WellType = 'D')
    LEFT JOIN HWell w_tot ON w_tot.PKey = wd.WellKey
WHERE wd.comment = 'PA'
    AND wd.event = 'WELLSTATUS'
    AND (YEAR(wd.eventdate) >= (YEAR(GETDATE()) - 4) AND YEAR(wd.eventdate) <= YEAR(GETDATE()))
GROUP BY YEAR(wd.eventdate)

查询有效,但我想转置 table,因此年份作为列名列在顶部,总计列在底部是一行。

这是从上面的查询生成的 table:

Year Oil Wells Gas Wells Service Wells Dry Holes Totals
2017 6 7 1 1 15
2018 15 23 5 6 49
2019 7 6 4 5 22
2020 10 16 4 0 30
2021 24 23 3 3 53

这是我想要的:

Well Types 2021 2020 2019 2018 2017
Oil Wells 24 10 7 15 6
Gas Wells 23 16 6 23 7
Service Wells 3 4 4 5 1
Dry Holes 3 0 5 6 1
Totals 53 30 22 49 15

我想我需要使用 PIVOT 来旋转 table,但怀疑我可能还需要使用 UNPIVOT 来获得我正在寻找的结果。我在想我可以将第一个 table 中的数据插入到名为“#wellsPluggedTempTbl”的临时 table 中。在那之后,也许我可以使用动态 sql 来生成结果。

这是我目前的情况:

DECLARE @colsPivot AS NVARCHAR(MAX)
DECLARE @query  AS NVARCHAR(MAX)

INSERT INTO #wellsPluggedTempTbl([Year], [Oil Wells], [Gas Wells], [Service Wells], [Dry Holes], Totals)
SELECT
    YEAR(wd.eventdate) AS [Year],
    ISNULL(COUNT(DISTINCT w_oil.WellID), 0) AS [Oil Wells],
    ISNULL(COUNT(DISTINCT w_gas.WellID), 0) AS [Gas Wells],
    ISNULL(COUNT(DISTINCT w_service.WellID), 0) AS [Service Wells],
    ISNULL(COUNT(DISTINCT w_dry.WellID), 0) AS [Dry Holes],
    ISNULL(COUNT(DISTINCT w_tot.WellID), 0) AS [Totals]
FROM HWellDate wd
    LEFT JOIN HWell w_oil ON (w_oil.PKey = wd.WellKey and w_oil.WellType = 'OW')
    LEFT JOIN HWell w_gas ON (w_gas.PKey = wd.WellKey and w_gas.WellType = 'GW')
    LEFT JOIN HWell w_service ON
    (
    w_service.PKey = wd.WellKey
    AND w_service.WellType IN ('WI','GI','GS','WD','WS','TW')
    )
    LEFT JOIN HWell w_dry ON (w_dry.PKey = wd.WellKey and w_dry.WellType = 'D')
    LEFT JOIN HWell w_tot ON w_tot.PKey = wd.WellKey
WHERE wd.comment = 'PA'
    AND wd.event = 'WELLSTATUS'
    AND (YEAR(wd.eventdate) >= (YEAR(GETDATE()) - 4) AND YEAR(wd.eventdate) <= YEAR(GETDATE()))
GROUP BY YEAR(wd.eventdate)

但是,我在 运行 之后得到了这个错误: “无效的对象名称‘#wellsPluggedTempTbl’。

对于最后的井型排序,我知道我需要使用这样的 CASE WHEN 语句:

ORDER BY
    CASE WellType
        WHEN 'Totals' THEN 5
        WHEN 'Dry Holes' THEN 4
        WHEN 'Service Wells' THEN 3
        WHEN 'Gas Wells' THEN 2
        WHEN 'Oil Wells' THEN 1
    END

Here 是一个 link 到 db<>fiddle ,其中我有一个产生结果的数据样本post。任何帮助,将不胜感激!谢谢。

如果您首先按井类型和年份分组,那么在外部查询中进行透视会变得更容易。

因为已经可以在子查询中计算出 Hole Category。

并且通过汇总和条件总和进行分组,它也会得到总计。

SELECT ISNULL(q.HoleCategory, 'Total') AS WellType
, ISNULL(SUM(CASE WHEN q.eventYear=2021 THEN q.Total END),0) AS [2021]
, ISNULL(SUM(CASE WHEN q.eventYear=2020 THEN q.Total END),0) AS [2020]
, ISNULL(SUM(CASE WHEN q.eventYear=2019 THEN q.Total END),0) AS [2019]
, ISNULL(SUM(CASE WHEN q.eventYear=2018 THEN q.Total END),0) AS [2018]
, ISNULL(SUM(CASE WHEN q.eventYear=2017 THEN q.Total END),0) AS [2017]
FROM
(
    SELECT w.WellType
    , YEAR(wd.eventDate) AS eventYear
    ,CASE 
     WHEN w.WellType = 'OW' THEN 'Oil Wells'
     WHEN w.WellType = 'GW' THEN 'Gas Wells'
     WHEN w.WellType IN ('WI','GI','GS','WD','WS','TW') THEN 'Service Wells'
     WHEN w.WellType = 'D' THEN 'Dry Holes'
     END AS HoleCategory 
    , COUNT(DISTINCT w.WellID) AS Total
    FROM HWellDate wd
    LEFT JOIN HWell w ON w.PKey = wd.WellKey
    WHERE wd.comment = 'PA'
      AND wd.event = 'WELLSTATUS'
      AND w.WellType IS NOT NULL
      AND YEAR(wd.eventdate) BETWEEN 2017 AND 2021
    GROUP BY w.WellType, YEAR(wd.eventDate)
) q
GROUP BY ROLLUP(q.HoleCategory)
ORDER BY
    CASE q.HoleCategory
    WHEN 'Oil Wells' THEN 1
    WHEN 'Gas Wells' THEN 2
    WHEN 'Service Wells' THEN 3
    WHEN 'Dry Holes' THEN 4
    ELSE 9
    END

你的做法是错误的。您应该只使用条件聚合,而不是旋转现有查询。

注意其他效率

  • 无需多次加入。只需加入一次并使用 CASE 表达式
  • 注意使用 CROSS APPLY (VALUES 创建和重新使用分组表达式
  • 使用GROUPING SETSROLLUP获取总计行,使用GROUPING()函数识别该行
  • 不要在 WHERE 中的列上使用函数,而是创建您需要的日期范围并对其进行过滤。
  • 如果您需要动态年份,而不是使用动态 SQL,只需调用列 ThisYear LastYear
SELECT
  WellType = CASE WHEN GROUPING(v.WellType) = 0 THEN v.WellType ELSE 'Totals' END,
  [2021] = COUNT(CASE WHEN [Year] = 2021 THEN 1 END),
  [2020] = COUNT(CASE WHEN [Year] = 2020 THEN 1 END),
  [2019] = COUNT(CASE WHEN [Year] = 2019 THEN 1 END),
  [2018] = COUNT(CASE WHEN [Year] = 2018 THEN 1 END),
  [2017] = COUNT(CASE WHEN [Year] = 2017 THEN 1 END)
FROM HWellDate wd
JOIN HWell w ON w.PKey = wd.WellKey
CROSS APPLY (VALUES(
    CASE WHEN w.WellType = 'OW' THEN 'Oil Wells'
         WHEN w.WellType = 'GW' THEN 'Gas Wells'
         WHEN w.WellType IN ('WI','GI','GS','WD','WS','TW') THEN 'Service Wells'
         WHEN w.WellType = 'D' THEN 'Dry Holes'
    END,
    YEAR(wd.eventdate)
)) v(WellType, Year)
WHERE wd.comment = 'PA'
  AND wd.event = 'WELLSTATUS'
  AND wd.eventdate >= DATEFROMPARTS(YEAR(GETDATE()) - 4, 1, 1)
  AND wd.eventdate <  DATEFROMPARTS(YEAR(GETDATE()) + 1, 1, 1)
  AND w.WellType IN ('OW','GW','WI','GI','GS','WD','WS','TW','D')
GROUP BY GROUPING SETS (
    (v.WellType),
    ()
 )
ORDER BY GROUPING(v.WellType) DESC,
    CASE v.WellType
        WHEN 'Dry Holes' THEN 4
        WHEN 'Service Wells' THEN 3
        WHEN 'Gas Wells' THEN 2
        WHEN 'Oil Wells' THEN 1
    END
;

db<>fiddle