如何根据sql中组中的日期集获取前7天的数据
Posted
技术标签:
【中文标题】如何根据sql中组中的日期集获取前7天的数据【英文标题】:How to get data for previous 7 days based on set of dates in groups in sql 【发布时间】:2016-10-16 04:14:34 【问题描述】:我正在通过这个论坛进行查询以获取前 7 天的数据,但大多数人都提供当前日期的数据。以下是我的要求:
我有一个表1如下:
这些是每周的开始日期,即星期一
from_date
2016-01-04
2016-01-11
2016-01-18
表 2
从星期一开始,我一周中的所有日子都在这里。例如:1 月 4 日 - 星期一到 1 月 10 日 - 星期日,其他星期也是如此。
get_date flag value
2016-01-04 N 4
2016-01-05 N 9
2016-01-06 Y 2
2016-01-07 Y 13
2016-01-08 Y 7
2016-01-09 Y 8
2016-01-10 Y 8
2016-01-11 Y 1
2016-01-12 Y 9
2016-01-13 N 8
2016-01-14 N 24
2016-01-15 N 8
2016-01-16 Y 4
2016-01-17 Y 5
2016-01-18 Y 9
2016-01-19 Y 2
2016-01-20 Y 8
2016-01-21 Y 4
2016-01-22 N 9
2016-01-23 N 87
2016-01-24 Y 3
预期结果 这里 wk 分别是每个开始结束日期的唯一编号 avg value 是该周日期值的平均值。
一周的最后 2 天是周末。
说 2016-01-09 和 2016-01-10 是周末
from_date get_date Wk Total_days Total_weekdays_flag_Y Total_weekenddays_flag_Y Avg_value
2016-01-04 2016-01-10 1 7 3 2 6.714285714
2016-01-11 2016-01-17 2 7 2 2 8.428571429
2016-01-18 2016-01-24 3 7 4 1 17.42857143
谁能帮我解决这个问题,因为我不擅长 sql。
谢谢
【问题讨论】:
你用的是什么数据库,什么版本? 【参考方案1】:select
from_date
, Wk
, count(case when day_of_week <=5 and flag = 'Y' then 1 end) as Total_weekdays_flag_Y
, count(case when day_of_week > 5 and flag = 'Y' then 1 end) as Total_weekenddays_flag_Y
, avg(value) as Avg_value
from (
select trunc(get_date,'IW') as from_date
, (trunc(get_date,'IW')- trunc(date'2016-01-04','IW'))/7 + 1 as Wk
, flag
, value
, get_date - trunc(get_date,'IW') as day_of_week
from Table_2)
group by from_date, Wk
order by from_date, Wk;
编辑:
/*generate some test_data for table 2*/
with table_2 (get_date, flag, value) as (
select date'2016-01-03' + level,
DECODE(mod(level,3),0,'Y','N'),
round(dbms_random.value(0,10))
from dual connect by level < 101
),
/*generate some test_weeks for table 1*/
table_1 (FROM_date) as (select date'2016-01-04' + (level-1)*7 from dual connect by level < 101 )
/*main query */
select
from_date
, Wk
, count(day_of_week) as total
, count(case when day_of_week <=5 and flag = 'Y' then 1 end) as Total_weekdays_flag_Y
, count(case when day_of_week > 5 and flag = 'Y' then 1 end) as Total_weekenddays_flag_Y
, avg(value) as Avg_value
from (
select last_value(from_date ignore nulls) over (order by get_date) as from_date
,last_value(Wk ignore nulls) over (order by get_date) as Wk
, flag
, value
, get_date - trunc(get_date,'IW') as day_of_week
from Table_2 t2
full join (select row_number() over (order by from_date) as wk,from_date from table_1) t1 on t2.get_date = t1.from_date
)
group by from_date, Wk
having count(day_of_week) > 0
order by from_date, Wk
【讨论】:
嗨迈克尔...我不能硬编码 2016-01-04,因为它可能会根据表中的内容而有所不同..我们可以假设最小日期。还有一件要考虑的事情是它是否如果一周的开始在一个月的 30 号左右并溢出到下个月,可以处理吗? 嗨,麦迪凯门。我没有得到你想要的。 2016-01-04 - 是星期一,之后的每 7 天都是星期一。可能您不是按常识按周分组,而是按表 1 中的间隔对您的表格进行分组?但不清楚在这种情况下什么是周末。你能解释一下吗 我添加了计算周期的案例 我的意思是每次它可能不会从 2016-01-04 开始。它可以是之前的任何一个星期一,也可以是 2015-12-28 等,而周末总是星期日。【参考方案2】:在下面的查询中,我在查询中创建了测试数据;在最终形式中,您将删除子查询 table_1
和 table_2
并使用其余部分。
该语法将从 Oracle 11.2 开始工作。在 Oracle 11.1 中,您需要将分解子查询中的列名移动到 select... from dual
部分。或者,由于您实际上只有一个子查询 (prep
) 和一个外部查询,因此您可以将 prep
编写为实际的内联子查询。
你的算术在第一周的平均水平似乎有所偏差。
在您的示例输出中,您使用get_date
表示一周的最后一天。这很奇怪,因为在table_2
中,该名称具有不同的含义。我在输出中使用了to_date
。我也没有显示total_days
- 那总是7,那么为什么要包括它呢? (如果不总是 7,那么有些事情你没有告诉我们;无论如何,count(...)
,如果应该是这样,很容易添加)。
with
-- begin test data, can be removed in final solution
table_1 ( from_date ) as (
select date '2016-01-04' from dual union all
select date '2016-01-11' from dual union all
select date '2016-01-18' from dual
)
,
table_2 ( get_date, flag, value ) as (
select date '2016-01-04', 'N', 4 from dual union all
select date '2016-01-05', 'N', 9 from dual union all
select date '2016-01-06', 'Y', 2 from dual union all
select date '2016-01-07', 'Y', 13 from dual union all
select date '2016-01-08', 'Y', 7 from dual union all
select date '2016-01-09', 'Y', 8 from dual union all
select date '2016-01-10', 'Y', 8 from dual union all
select date '2016-01-11', 'Y', 1 from dual union all
select date '2016-01-12', 'Y', 9 from dual union all
select date '2016-01-13', 'N', 8 from dual union all
select date '2016-01-14', 'N', 24 from dual union all
select date '2016-01-15', 'N', 8 from dual union all
select date '2016-01-16', 'Y', 4 from dual union all
select date '2016-01-17', 'Y', 5 from dual union all
select date '2016-01-18', 'Y', 9 from dual union all
select date '2016-01-19', 'Y', 2 from dual union all
select date '2016-01-20', 'Y', 8 from dual union all
select date '2016-01-21', 'Y', 4 from dual union all
select date '2016-01-22', 'N', 9 from dual union all
select date '2016-01-23', 'N', 87 from dual union all
select date '2016-01-24', 'Y', 3 from dual
),
-- end test data, continue actual query
prep ( get_date, flag, value, from_date, wd_flag ) as (
select t2.get_date, t2.flag, t2.value, t1.from_date,
case when t2.get_date - t1.from_date <= 4 then 'wd' else 'we' end
from table_1 t1 inner join table_2 t2
on t2.get_date between t1.from_date and t1.from_date + 6
)
select from_date,
from_date + 6 as to_date,
row_number() over (order by from_date) as wk,
count(case when flag = 'Y' and wd_flag = 'wd' then 1 end)
as total_weekday_Y,
count(case when flag = 'Y' and wd_flag = 'we' then 1 end)
as total_weekend_Y,
round(avg(value), 6) as avg_value
from prep
group by from_date;
输出:
FROM_DATE TO_DATE WK TOTAL_WEEKDAY_Y TOTAL_WEEKEND_Y AVG_VALUE
---------- ---------- ---- --------------- --------------- ----------
2016-01-04 2016-01-10 1 3 2 7.285714
2016-01-11 2016-01-17 2 2 2 8.428571
2016-01-18 2016-01-24 3 4 1 17.428571
【讨论】:
HI mathguy..感谢这个解决方案..它有效...我只是在想..如果一周中的某一天从 30 日或 31 日开始,假设会有一个..虽然不确定 @maddykemen - 解决方案应该可以正常工作 - 除非“月”、“年”、“周从一个月开始但在另一个结束”等有特殊含义。这是我的解决方案:它需要table_1
中的每个日期(您有责任确保它们都是星期一,并且您需要在最终报告中包含所有星期一)。然后对于这些日期中的每一个,它将获取table_2
中该日期和该日期 + 6(同一周的星期日)之间的所有行。 (下续)
计算不关心这些日期是一个月还是一年 - 它们在所有情况下都可以正常工作。无需调整。以上是关于如何根据sql中组中的日期集获取前7天的数据的主要内容,如果未能解决你的问题,请参考以下文章
如何使用窗口函数获取每个日期值的今天、过去 7 天、过去 30 天的指标?