Sql Oracle select中使用窗口功能运行的总计(累积列)有什么问题?
我有一个查询,在一列中包含Sql Oracle select中使用窗口功能运行的总计(累积列)有什么问题?,sql,oracle,window-functions,cumulative-sum,Sql,Oracle,Window Functions,Cumulative Sum,我有一个查询,在一列中包含0或1。出于演示目的,我将1替换为77,以便更容易看到: select dates.d the_date , case TO_CHAR(dates.d, 'd') when '7' then 0 when '1' then 0 else 77 end as is_workday from (SELECT (to_date('01.01.2019','dd.mm.yyyy') + (LEVEL -1)) AS d FROM DUAL conn
0
或1
。出于演示目的,我将1
替换为77
,以便更容易看到:
select dates.d the_date
, case TO_CHAR(dates.d, 'd') when '7' then 0 when '1' then 0
else 77
end as is_workday
from (SELECT (to_date('01.01.2019','dd.mm.yyyy') + (LEVEL -1))
AS d FROM DUAL connect by level <=(
to_date('31.12.2020','dd.mm.yyyy')-(to_date('01.01.2019','dd.mm.yyyy')))
) as dates
我想在是_workday
的基础上添加一个运行总数,这意味着一个累积值。我确信Oracles的窗口功能就是为此而设计的
SELECT x.the_date
, x.is_workday
, sum(x.is_workday) over (
partition by x.the_date -- define the window
order by x.the_date asc -- order inside window
rows between unbounded preceding -- sum to top
and current row -- sum ending here
) as workdays_cumul
FROM (
select dates.d the_date
, case TO_CHAR(dates.d, 'd') when '7' then 0 when '1' then 0
else 77
end as is_workday
from (SELECT (to_date('01.01.2019','dd.mm.yyyy') + (LEVEL -1))
AS d FROM DUAL connect by level <=(
to_date('31.12.2020','dd.mm.yyyy')-(to_date('01.01.2019','dd.mm.yyyy')))
) as dates
) x
order by x.the_date
;
显然应该是:
| THE_DATE | IS_WORKDAY | WORKDAYS_CUMUL |
| 2019-01-01 00:00:00 | 77 | 77 |
| 2019-01-02 00:00:00 | 77 | 154 |
| 2019-01-03 00:00:00 | 77 | 231 |
...
我以为会是这样的:
--对sum(x.is_workday)
-值进行求和77
——每个窗口/部分/部件各有一行(在我的例子中)按x.the_日期进行分区
——按日期排序这些行按x排序。日期asc
--第一行之间的和无界前一行之间的行
--。。。和当前行和当前行
我在这里遗漏了什么?删除查询中的
PARTITION BY
子句,因为窗口的作用域是整个查询,而不是每个单独的日期:
SELECT the_date
, is_workday
, sum(is_workday) over (
ORDER BY the_date asc -- order inside window
ROWS BETWEEN unbounded preceding -- sum to top
AND current row -- sum ending here
) as workdays_cumul
FROM (
select d the_date
, CASE
WHEN d - TRUNC( d, 'IW' ) IN ( 5, 6 )
THEN 0
ELSE 1
END AS is_workday
FROM (
SELECT DATE '2019-01-01' + LEVEL -1 AS d
FROM DUAL
connect by level <= DATE '2020-12-31' - DATE '2019-01-01'
)
)
order by the_date;
dbfiddle按日期划分将每个日期的值相加(基本上按日期分组)。移除它。@JohnHC ohh。。。。所以我必须定义“一个大窗口”而不是“许多小窗口”。。。我懂了!替换为
按x按1顺序分区。日期asc
似乎做到了这一点!谢谢,你可以回答这个问题。按1分区是否是“删除它”的正确方式?与您的问题无关,但to_CHAR(dates.d,'d')
是;例如,在英国和美国,你会得到不同的答案,因为一周从不同的日子开始。@AlexPoole谢谢。我确实用J
和MOD 7
找到了一个解决方案,我想知道这是为什么。我希望oracle能在他们的文档中提到这一点,格式为D
实际上,默认情况下,前一行和当前行之间的行是无界的
,因此您可以简单地将总和(x.is\u workday)写入(按x.u日期排序)
| THE_DATE | IS_WORKDAY | WORKDAYS_CUMUL |
| 2019-01-01 00:00:00 | 77 | 77 |
| 2019-01-02 00:00:00 | 77 | 154 |
| 2019-01-03 00:00:00 | 77 | 231 |
...
SELECT the_date
, is_workday
, sum(is_workday) over (
ORDER BY the_date asc -- order inside window
ROWS BETWEEN unbounded preceding -- sum to top
AND current row -- sum ending here
) as workdays_cumul
FROM (
select d the_date
, CASE
WHEN d - TRUNC( d, 'IW' ) IN ( 5, 6 )
THEN 0
ELSE 1
END AS is_workday
FROM (
SELECT DATE '2019-01-01' + LEVEL -1 AS d
FROM DUAL
connect by level <= DATE '2020-12-31' - DATE '2019-01-01'
)
)
order by the_date;
THE_DATE | IS_WORKDAY | WORKDAYS_CUMUL
:-------- | ---------: | -------------:
01-JAN-19 | 1 | 1
02-JAN-19 | 1 | 2
03-JAN-19 | 1 | 3
04-JAN-19 | 1 | 4
05-JAN-19 | 0 | 4
06-JAN-19 | 0 | 4
07-JAN-19 | 1 | 5
08-JAN-19 | 1 | 6
09-JAN-19 | 1 | 7
...
24-DEC-20 | 1 | 518
25-DEC-20 | 1 | 519
26-DEC-20 | 0 | 519
27-DEC-20 | 0 | 519
28-DEC-20 | 1 | 520
29-DEC-20 | 1 | 521
30-DEC-20 | 1 | 522