作为子查询一部分的 SQL 列的总计 运行
Running total for SQL column that is part of subquery
这里有很多帖子描述了如何进行 运行 总计,但我遇到的情况是 运行 总计需要是使用子查询计算的列的总计(这意味着我当前的 ORDER BY 导致查询失败)
我有一个 table 显示每个时间段的金额,如下所示:
TimePeriod Amount
2022-03-31 396
2022-03-31 16
2022-03-31 84
2021-12-31 842
2021-12-31 57
2021-09-30 652
2021-09-30 25
2021-09-30 173
在我的查询中,我需要找到每个时间段占总数的百分比。我所做的是:
SELECT
TimePeriod,
SUM(Amount) AS 'Total Per Period',
CAST( ROUND( SUM(Amount)/(SELECT SUM(Amount) FROM MyDatabase.MyTable),3) AS DECIMAL(12,3)) AS 'Percentage of Total'
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod
ORDER BY
TimePeriod DESC
这给了我一个正确的输出,像这样:
TimePeriod Total per Period Percentage of total
2022-03-31 496 0.221
2021-12-31 899 0.400
2021-09-30 850 0.379
我想要做的是在 'Percentage of total' 列中添加一个 运行 总数,例如:
TimePeriod Total per Period Percentage of total Running total percentage
2022-03-31 496 0.221 0.221
2021-12-31 899 0.400 0.621
2021-09-30 850 0.379 1.000
我试图做的是首先将它添加到第一个 SELECT 子句中,但这不起作用,因为它是一个只存在于我的查询中的列。然后我尝试对 select 做一个 select,像这样:
SELECT
TimePeriod,
'Total Per Period',
'Percentage of Total',
SUM('Percentage of Total') OVER (ORDER BY TimePeriod)
FROM
(SELECT
TimePeriod,
SUM(Amount) AS 'Total Per Period',
CAST( ROUND( SUM(Amount)/(SELECT SUM(Amount) FROM MyDatabase.MyTable),3) AS DECIMAL(12,3)) AS 'Percentage of Total'
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod
ORDER BY
TimePeriod DESC)
这会抛出错误,指出子查询中不允许使用最后一个 ORDER BY。相反,删除 ORDER BY 表示语法不正确。我猜问题是我有一个引用子查询结果的子查询,但我不确定如何解决这个问题。我的查询中似乎缺少什么?
您可能需要使用[]
来包含列名而不是'
,这意味着字符串值,我们还需要给子查询一个别名。
SELECT
TimePeriod,
[Total Per Period],
[Percentage of Total],
SUM([Percentage of Total]) OVER (ORDER BY TimePeriod)
FROM
(SELECT
TimePeriod,
SUM(Amount) AS 'Total Per Period',
CAST( ROUND( SUM(Amount)/(SELECT SUM(Amount) FROM MyDatabase.MyTable),3) AS DECIMAL(12,3)) AS 'Percentage of Total'
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod) t1
ORDER BY
TimePeriod DESC
您有一些语法错误,还有一些需要改进的地方:
- 正如另一个答案中提到的,派生的 table 需要一个别名
- 如有必要,请使用
[]
引用列名(最好一开始就不要使用此类列名)。
- 您不能在派生的 table 或子查询中包含
ORDER BY
,这样做也没有意义。
- 您可以用
SUM(SUM) OVER ()
window 函数替换 SELECT SUM
子查询。
- 如果
TimePeriod
可能有重复,运行 总计 window 函数必须有 ROWS UNBOUNDED PRECEDING
。它也更快。
- 因为您是按
TimePeriod DESC
排序的,所以 运行 总计的顺序与主 ORDER BY
相同但使用 ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
可能会更快得出相同的结果。好处是查询计划中少了一种排序。
SELECT
TimePeriod,
[Total Per Period],
[Percentage of Total],
SUM([Percentage of Total]) OVER (ORDER BY TimePeriod DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
FROM
(SELECT
TimePeriod,
SUM(Amount) AS [Total Per Period],
CAST( ROUND( SUM(Amount) / SUM(SUM(Amount)) OVER () , 3) AS DECIMAL(12,3)) AS [Percentage of Total]
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod
) t
ORDER BY
TimePeriod DESC;
进一步的改进是将整个事情合并为一个级别:
SELECT
TimePeriod,
SUM(Amount) AS [Total Per Period],
CAST( ROUND(
SUM(Amount) /
SUM(SUM(Amount)) OVER ()
, 3) AS DECIMAL(12,3)) AS [Percentage of Total],
CAST( ROUND(
SUM(SUM(Amount)) OVER (ORDER BY TimePeriod DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) /
SUM(SUM(Amount)) OVER ()
, 3) AS DECIMAL(12,3))
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod
ORDER BY
TimePeriod DESC;
请注意,由于四舍五入,结果可能略有不同。
这是我对你的问题的解决方案。我用Oracle解决了。
with flo as (
select
timeperiod,
sum(amount) as amount,
cast((sum(amount) / (select sum(amount) from da ))as decimal(10,6)) *100.0 as percent_of_total
from yourtable
group by timeperiod
)
select
timeperiod,
amount,
percent_of_total,
sum(percent_of_total) over (order by timeperiod desc ) as running
from flo;
这里有很多帖子描述了如何进行 运行 总计,但我遇到的情况是 运行 总计需要是使用子查询计算的列的总计(这意味着我当前的 ORDER BY 导致查询失败)
我有一个 table 显示每个时间段的金额,如下所示:
TimePeriod Amount
2022-03-31 396
2022-03-31 16
2022-03-31 84
2021-12-31 842
2021-12-31 57
2021-09-30 652
2021-09-30 25
2021-09-30 173
在我的查询中,我需要找到每个时间段占总数的百分比。我所做的是:
SELECT
TimePeriod,
SUM(Amount) AS 'Total Per Period',
CAST( ROUND( SUM(Amount)/(SELECT SUM(Amount) FROM MyDatabase.MyTable),3) AS DECIMAL(12,3)) AS 'Percentage of Total'
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod
ORDER BY
TimePeriod DESC
这给了我一个正确的输出,像这样:
TimePeriod Total per Period Percentage of total
2022-03-31 496 0.221
2021-12-31 899 0.400
2021-09-30 850 0.379
我想要做的是在 'Percentage of total' 列中添加一个 运行 总数,例如:
TimePeriod Total per Period Percentage of total Running total percentage
2022-03-31 496 0.221 0.221
2021-12-31 899 0.400 0.621
2021-09-30 850 0.379 1.000
我试图做的是首先将它添加到第一个 SELECT 子句中,但这不起作用,因为它是一个只存在于我的查询中的列。然后我尝试对 select 做一个 select,像这样:
SELECT
TimePeriod,
'Total Per Period',
'Percentage of Total',
SUM('Percentage of Total') OVER (ORDER BY TimePeriod)
FROM
(SELECT
TimePeriod,
SUM(Amount) AS 'Total Per Period',
CAST( ROUND( SUM(Amount)/(SELECT SUM(Amount) FROM MyDatabase.MyTable),3) AS DECIMAL(12,3)) AS 'Percentage of Total'
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod
ORDER BY
TimePeriod DESC)
这会抛出错误,指出子查询中不允许使用最后一个 ORDER BY。相反,删除 ORDER BY 表示语法不正确。我猜问题是我有一个引用子查询结果的子查询,但我不确定如何解决这个问题。我的查询中似乎缺少什么?
您可能需要使用[]
来包含列名而不是'
,这意味着字符串值,我们还需要给子查询一个别名。
SELECT
TimePeriod,
[Total Per Period],
[Percentage of Total],
SUM([Percentage of Total]) OVER (ORDER BY TimePeriod)
FROM
(SELECT
TimePeriod,
SUM(Amount) AS 'Total Per Period',
CAST( ROUND( SUM(Amount)/(SELECT SUM(Amount) FROM MyDatabase.MyTable),3) AS DECIMAL(12,3)) AS 'Percentage of Total'
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod) t1
ORDER BY
TimePeriod DESC
您有一些语法错误,还有一些需要改进的地方:
- 正如另一个答案中提到的,派生的 table 需要一个别名
- 如有必要,请使用
[]
引用列名(最好一开始就不要使用此类列名)。 - 您不能在派生的 table 或子查询中包含
ORDER BY
,这样做也没有意义。 - 您可以用
SUM(SUM) OVER ()
window 函数替换SELECT SUM
子查询。 - 如果
TimePeriod
可能有重复,运行 总计 window 函数必须有ROWS UNBOUNDED PRECEDING
。它也更快。 - 因为您是按
TimePeriod DESC
排序的,所以 运行 总计的顺序与主ORDER BY
相同但使用ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
可能会更快得出相同的结果。好处是查询计划中少了一种排序。
SELECT
TimePeriod,
[Total Per Period],
[Percentage of Total],
SUM([Percentage of Total]) OVER (ORDER BY TimePeriod DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
FROM
(SELECT
TimePeriod,
SUM(Amount) AS [Total Per Period],
CAST( ROUND( SUM(Amount) / SUM(SUM(Amount)) OVER () , 3) AS DECIMAL(12,3)) AS [Percentage of Total]
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod
) t
ORDER BY
TimePeriod DESC;
进一步的改进是将整个事情合并为一个级别:
SELECT
TimePeriod,
SUM(Amount) AS [Total Per Period],
CAST( ROUND(
SUM(Amount) /
SUM(SUM(Amount)) OVER ()
, 3) AS DECIMAL(12,3)) AS [Percentage of Total],
CAST( ROUND(
SUM(SUM(Amount)) OVER (ORDER BY TimePeriod DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) /
SUM(SUM(Amount)) OVER ()
, 3) AS DECIMAL(12,3))
FROM
MyDatabase.MyTable
GROUP BY
TimePeriod
ORDER BY
TimePeriod DESC;
请注意,由于四舍五入,结果可能略有不同。
这是我对你的问题的解决方案。我用Oracle解决了。
with flo as (
select
timeperiod,
sum(amount) as amount,
cast((sum(amount) / (select sum(amount) from da ))as decimal(10,6)) *100.0 as percent_of_total
from yourtable
group by timeperiod
)
select
timeperiod,
amount,
percent_of_total,
sum(percent_of_total) over (order by timeperiod desc ) as running
from flo;