Sql 当其他值更改时返回一个值
我有一个查询,它返回以下内容,除了最后一列,这是我需要弄清楚如何创建的。对于每个给定的Sql 当其他值更改时返回一个值,sql,oracle,analytic-functions,Sql,Oracle,Analytic Functions,我有一个查询,它返回以下内容,除了最后一列,这是我需要弄清楚如何创建的。对于每个给定的ObservationID,我需要返回状态更改的日期;类似于LEAD()函数的东西,它将接受条件而不仅仅是偏移量。能做到吗 我需要计算列的更改日期;它应该是状态不是当前状态的最后日期 +---------------+--------+-----------+--------+-------------+ | ObservationID | Region | Date | Status | Chang
ObservationID
,我需要返回状态更改的日期;类似于LEAD()函数的东西,它将接受条件而不仅仅是偏移量。能做到吗
我需要计算列的更改日期;它应该是状态不是当前状态的最后日期
+---------------+--------+-----------+--------+-------------+
| ObservationID | Region | Date | Status | Change Date | <-This field
+---------------+--------+-----------+--------+-------------+
| 1 | 10 | 1/3/2012 | Ice | 1/4/2012 |
| 2 | 10 | 1/4/2012 | Water | 1/6/2012 |
| 3 | 10 | 1/5/2012 | Water | 1/6/2012 |
| 4 | 10 | 1/6/2012 | Gas | 1/7/2012 |
| 5 | 10 | 1/7/2012 | Ice | |
| 6 | 20 | 2/6/2012 | Water | 2/10/2012 |
| 7 | 20 | 2/7/2012 | Water | 2/10/2012 |
| 8 | 20 | 2/8/2012 | Water | 2/10/2012 |
| 9 | 20 | 2/9/2012 | Water | 2/10/2012 |
| 10 | 20 | 2/10/2012 | Ice | |
+---------------+--------+-----------+--------+-------------+
+---------------+--------+-----------+--------+-------------+
|ObservationID | Region | Date | Status | Change Date |我在清理日期之间的重叠和重复行时经常这样做。
不过,您的情况要简单得多,因为您只有“开始日期”:
设置测试数据
create table observations(
observation_id number not null
,region number not null
,observation_date date not null
,status varchar2(10) not null
);
insert
into observations(observation_id, region, observation_date, status)
select 1, 10, date '2012-03-01', 'Ice' from dual union all
select 2, 10, date '2012-04-01', 'Water' from dual union all
select 3, 10, date '2012-05-01', 'Water' from dual union all
select 4, 10, date '2012-06-01', 'Gas' from dual union all
select 5, 10, date '2012-07-01', 'Ice' from dual union all
select 6, 20, date '2012-06-02', 'Water' from dual union all
select 7, 20, date '2012-07-02', 'Water' from dual union all
select 8, 20, date '2012-08-02', 'Water' from dual union all
select 9, 20, date '2012-09-02', 'Water' from dual union all
select 10, 20, date '2012-10-02', 'Ice' from dual;
commit;
以下查询有三个关注点:
识别重复信息(记录显示与先前记录相同)
忽略重复的录音
确定“下一次”变更的日期
范本条款(10g+)可以以简洁的方式实现这一点:
SQL> create table observation(ObservationID , Region ,obs_date, Status)
2 as
3 select 1, 10, date '2012-03-01', 'Ice' from dual union all
4 select 2, 10, date '2012-04-01', 'Water' from dual union all
5 select 3, 10, date '2012-05-01', 'Water' from dual union all
6 select 4, 10, date '2012-06-01', 'Gas' from dual union all
7 select 5, 10, date '2012-07-01', 'Ice' from dual union all
8 select 6, 20, date '2012-06-02', 'Water' from dual union all
9 select 7, 20, date '2012-07-02', 'Water' from dual union all
10 select 8, 20, date '2012-08-02', 'Water' from dual union all
11 select 9, 20, date '2012-09-02', 'Water' from dual union all
12 select 10, 20, date '2012-10-02', 'Ice' from dual ;
Table created.
SQL> select ObservationID, obs_date, Status, status_change
2 from observation
3 model
4 dimension by (Region, obs_date, Status)
5 measures ( ObservationID, obs_date obs_date2, cast(null as date) status_change)
6 rules (
7 status_change[any,any,any] = min(obs_date2)[cv(Region), obs_date > cv(obs_date), status != cv(status)]
8 )
9 order by 1;
OBSERVATIONID OBS_DATE STATU STATUS_CH
------------- --------- ----- ---------
1 01-MAR-12 Ice 01-APR-12
2 01-APR-12 Water 01-JUN-12
3 01-MAY-12 Water 01-JUN-12
4 01-JUN-12 Gas 01-JUL-12
5 01-JUL-12 Ice
6 02-JUN-12 Water 02-OCT-12
7 02-JUL-12 Water 02-OCT-12
8 02-AUG-12 Water 02-OCT-12
9 02-SEP-12 Water 02-OCT-12
10 02-OCT-12 Ice
小提琴:
i、 e.我们将根据区域、日期和状态进行尺寸标注,因为我们希望查看具有相同区域的单元格,但得到状态不同的第一个日期
我们还必须测量日期,因此我创建了一个别名obs_date2
,我们需要一个新列status_change
来保存状态更改的日期
这一行为我们完成了所有工作:
status_change[any,any,any] = min(obs_date2)[cv(Region), obs_date > cv(obs_date), status != cv(status)]
它说,对于我们的三个维度,只看具有相同区域的行(cv(region),
),以及日期紧跟当前行日期的行(obs\u date>cv(obs\u date)
),并且状态与当前行不同(status!=cv(status)
)最后,获取满足这组条件的最小日期(min(obs\u date2)
),并将其分配给状态更改
。左边的any,any,any
部分表示此计算适用于所有行。我曾多次尝试理解MODEL子句,但从未真正理解它,因此我想添加另一个解决方案
此解决方案采用了Ronnis所做的一些工作,但使用了LEAD函数的ignorenulls
子句。我认为这只是Oracle11的新增功能,但如果需要,您可能会将其替换为Oracle10的FIRST\u VALUE
函数
select
observation_id,
region,
observation_date,
status,
lead(case when is_change = 'Y' then observation_date end) ignore nulls
over (partition by region order by observation_date) as change_observation_date
from (
select
a.observation_id,
a.region,
a.observation_date,
a.status,
case
when status = lag(status) over (partition by region order by observation_date)
then null
else 'Y' end as is_change
from observations a
)
order by 1
至于代码,我需要它为每个地区的每个特定状态提供开始和结束日期,即a地区的冻结持续了多长时间?我尝试过子查询,它为我提供每个状态的最早日期,但无法将它们与状态的正确更改正确配对。与LEAD类似的功能是理想的,但比下一条记录的范围更广。冰/水/气体不是真实的数据,只是代表我的问题…真实的查询很长,肯定会浪费你的时间。这是一个简单的选择,其中四列来自四个不同的表,“更改日期”是我无法创建的列。如果这还不够的话,请道歉,这是一个新手,我不想浪费你的时间。@David:这里的很多SQL问题都倾向于使用SQL Fiddle来显示你的架构设置和你迄今为止所做的尝试;这里有一个开始的地方:您能添加一个到目前为止您已经尝试过的示例查询吗?不幸的是,目前在fam度假,无法测试这些…将在下周试用后立即报告!Dazzal的建模方法正在发挥作用,将与Ronnis和Mike的建模方法进行比较,显然可以使用这种方法……Ronnis,非常感谢,将尝试这种方法,并让大家知道下周有多少条通往罗马的路?非常感谢,迈克,下个星期我的结果Dazzal,我先尝试了这个方法,它很有魅力。在将其调整到真实数据后,只需添加一个唯一的引用即可。我已经向模特迈出了第一步!非常感谢,我们将了解如何给你适当的网站荣誉。
select
observation_id,
region,
observation_date,
status,
lead(case when is_change = 'Y' then observation_date end) ignore nulls
over (partition by region order by observation_date) as change_observation_date
from (
select
a.observation_id,
a.region,
a.observation_date,
a.status,
case
when status = lag(status) over (partition by region order by observation_date)
then null
else 'Y' end as is_change
from observations a
)
order by 1