当有 '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 SETS
或ROLLUP
获取总计行,使用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
;
我整理了一个查询,显示 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 SETS
或ROLLUP
获取总计行,使用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
;