处理连续行计算
Posted
技术标签:
【中文标题】处理连续行计算【英文标题】:Dealing with consecutive rows calculations 【发布时间】:2012-09-12 02:59:54 【问题描述】:假设以下情况:
第 1 周: 0 以前的案例 10 个新病例 3 已解决的案例 第 2 周: 7 以前的案例 13 个新病例 15 解决案例 第 3 周: 5 以前的案例 6 个新病例 7 解决案例此信息存储在排序的恢复表中:
RESUME_TABLE:
WEEK | TOTAL_NEW | TOTAL_SOLVED
1 | 10 | 3
2 | 13 | 15
3 | 6 | 7
我很难构建查询以获得以下结果:
REPORT_TABLE:
WEEK | PREV_TOTAL | NEW_CASES | SOLVED_CASES | NEW_TOTAL
1 | 0 | 10 | 3 | 7
2 | 7 | 13 | 15 | 5
3 | 5 | 6 | 7 | 4
NEW_TOTAL = PREV_TOTAL + NEW_CASES - SOLVED_CASES
这个想法似乎很简单,尽管我一直在努力将PREV_TOTAL
带到下一行以便继续。
我正在尝试使用 RESUME
表 (Oracle 11g) 上的视图来执行此操作。
有人可以帮我提供一些示例代码吗?
【问题讨论】:
【参考方案1】:分析函数非常简单整洁:
12:57:06 HR@vm_xe> l
1 select week
2 ,lag(total_cases_by_now - total_solved_by_now) over (order by week) prev_total
3 ,total_new new_cases
4 ,total_solved solved_cases
5 ,total_cases_by_now - total_solved_by_now new_total
6 from (
7 select week
8 ,total_new
9 ,total_solved
10 ,sum(total_new) over(order by week asc) as total_cases_by_now
11 ,sum(total_solved) over (order by week asc) as total_solved_by_now
12 from resume_table
13* )
12:57:07 HR@vm_xe> /
WEEK PREV_TOTAL NEW_CASES SOLVED_CASES NEW_TOTAL
---------- ------------ ---------- ------------ ----------
1 10 3 7
2 7 13 15 5
3 5 6 7 4
3 rows selected.
Elapsed: 00:00:00.01
【讨论】:
很酷,我试图达到这样的目标,尽管我从来没有花时间好好学习分析:( 我发现这个解决方案非常优雅,但我在添加更多细节时遇到了问题。例如,我还想按类型分隔案例,所以我尝试添加,sum(total_solved) over (partition by case_type, week order by week asc)
但没有奏效(是的,我在简历表上有“case_type”列,对 total_cases_by_now
字段也做了同样的事情并将其添加到许多 select
语句中)。这是正确的做法吗?
从partition by
中删除week
以供初学者使用。这会将分析窗口折叠为仅一周,而不是当前类型的所有周。而且您也需要对滞后功能进行分区,顺便说一句
@filippo 你能用你当前的分区测试用例更新你的初始帖子吗?
嗨,最后一次更新,我设法重现了确切的问题。介意看看这个小提琴:sqlfiddle.com/#!4/aaedc/1【参考方案2】:
您可以使用MODEL 子句解决这个问题:
with resume_table as
(
select 1 week, 10 total_new, 3 total_solved from dual union all
select 2 week, 13 total_new, 15 total_solved from dual union all
select 3 week, 6 total_new, 7 total_solved from dual
)
select week, prev_total, total_new, total_solved, new_total
from resume_table
model
dimension by (week)
measures (total_new, total_solved, 0 prev_total, 0 new_total)
rules sequential order
(
new_total[any] order by week =
nvl(new_total[cv(week)-1], 0) + total_new[cv()] - total_solved[cv()]
,prev_total[any] order by week = nvl(new_total[cv(week)-1], 0)
)
order by week;
尽管这假设 WEEK 始终是一个连续的数字。如果不是这样,您将需要添加row_number()
。否则,-1
可能不会引用之前的值。
看到这个SQL Fiddle。
【讨论】:
这很花哨。我会仔细看一看。谢谢。 嘿,关于你的模型的几个问题。一周的事情实际上不一定是连续的,但我并没有像你提到的那样添加row_number()
而不会破坏它(对不起,我以前从未使用过模型)。实际上,我不仅在尝试这样做,而且还在数据中添加了更多维度,这在我尝试这样做的任何方面都给我带来了麻烦。如果你能帮我一把:sqlfiddle.com/#!4/aaedc/1 .. 外部group by
只是为了检查数学,我真正感兴趣的是with
子句中的查询。谢谢!【参考方案3】:
在RESUME_TABLE
中添加一列(或者创建一个视图,我认为可能会更好):
RESUME_LEFT
WEEK | LEFT
1 | 7
2 | -2
3 | -1
类似这样的:
CREATE VIEW resume_left
(SELECT week,total_new-total_solved "left" FROM resume_table)
所以在REPORT_TABLE
,你可以有这样的定义:
PREV_TOTAL=(SELECT sum(left) FROM RESUME_LEFT WHERE week<REPORT_TABLE.week)
编辑
好的,视图是不必要的:
PREV_TOTAL=(SELECT sum(total_new)-sum(total_solved)
FROM resume_table
WHERE week<REPORT_TABLE.week)
【讨论】:
谢谢,虽然它并没有真正起作用。我实际的“周”列是一个日期,这会是一个问题吗?此外,我对示例(数字)进行了一些更改以使其更清晰。 @filippo 它应该可以工作,因为sum(total_new)-sum(total_solved) where week<report.week
实际上是您的prev_total
的数学定义。 date
类型应该不是问题,因为它在 Oracle 中具有可比性,并且与示例中的 week
具有相同的顺序(越旧意味着值越小)。
是的,我认为这是有道理的,尽管它只会返回空列。这是实际的代码:pastebin.com/Cs9BLr5w(很简单,只是更改了标签以匹配这里的问题)。介意看看吗?
@filippo 抱歉,我现在没有可访问的 Oracle,所以我必须考虑调试实际代码...你能看看这是否有效吗? pastebin.com/bnSQ5bHG
确实如此。先生,您让我的夜晚值得。非常感谢。以上是关于处理连续行计算的主要内容,如果未能解决你的问题,请参考以下文章