有人能给我一个棘手的SQL问题的线索。我搜索了类似的问题,最近的方法似乎是这样,但它不是我的问题的解决方案: Oracle - grouping between pairs of records
我知道这可以通过PL / SQL过程实现,但在这种情况下(Oracle)SQL是必要的。 我正在寻找一个Oracle SQL SELECT来隔离ID = 4和5的普通表的特殊记录。该表仅包含2列:ID和DATE 它包含这样的数据:
ID DATE REMARK (this row is not part of table!)
--------------- ------------------------------------------
2 01-JAN-2013
4 02-JAN-2013 A
7 03-JAN-2013
5 05-JAN-2013 A
6 07-JAN-2013
4 08-JAN-2013 B
1 11-JAN-2013
5 12-JAN-2013 B
... more follows
ID 4和5的组如果及时跟随,则属于一起。因此,我标记为“A”的行属于一起,“B”也是如此。 两个As和两个B属于一起,因为它们在日期中是连续的。 现在我想要的是一个返回4列的SELECT,i。即一行中的两行A,以及一行中的行B.
所以输出应该如下所示:
ID4 DATE4 ID5 DATE5 Comment (no column, just comment)
--------------------------------- ------------------------------------
4 02-JAN-2013 5 05-JAN-2013 First set of 4 and 5
4 08-JAN-2013 5 12-JAN-2013 Second set of 4 and 5
...more follows
(列ID4和ID5当然已经过时,仅用于演示目的)
我希望自己能理解?有人有想法吗?
更新: 感谢您的想法和选择,我很抱歉在提出问题时不够清楚。 只应考虑4对和5对,并且只能按日期的升序排列。对于上面的例子,Alex Pool和Florin Ghita的解决方案很棒,谢谢! 4er的日期必须小于或等于5er的日期。如果有一个4er或5er没有匹配的伙伴,可以忽略它。
但是这里有另一个包含真实数据和陷阱的示例(这里的解决方案失败了):按时间顺序遍历数据,有2行,连续5行。
4 16.03.2012 17:49:28 A
5 10.05.2012 09:38:56 A1 Either A1 is possible
5 12.06.2012 07:51:03 A2 or A2 whichever is easier to code
4 12.06.2012 08:47:52 B
5 02.08.2012 11:27:43 B
4 03.08.2012 13:24:54 C
5 03.08.2012 14:14:07 C
4 04.08.2012 15:00:00 should be ignored, as there is no following 5er
通缉输出:
4 16.03.2012 17:49:28 5 10.05.2012 09:38:56 (alternat.: 5 12.06.2012 07:51:03)
4 12.06.2012 08:47:52 5 02.08.2012 11:27:43
4 03.08.2012 13:24:54 5 03.08.2012 14:14:07
建议的SELECTS失败,因为他们不认为4er必须在5er之前。如果没有相应的合作伙伴,请忽略此行。我没有说清楚,对不起。
非常感谢你 FRIEDHELM
答案 0 :(得分:2)
与其他评论者一样,我并不完全确定我会关注,但如果您只想查看ID 4和5并希望按日期顺序匹配它们,您可以执行以下操作:
with t as (
select id, dt, row_number() over (partition by id order by dt) as rn
from t42
where id in (4, 5)
)
select t4.id as id4, t4.dt as date4, t5.id as id5, t5.dt as date5,
case t4.rn when 1 then 'First' when 2 then 'Second' when 3 then 'Third' end
|| ' set of 4 and 5' as "Comment"
from t t4
join t t5 on t5.rn = t4.rn
where t4.id = 4
and t5.id = 5
order by t4.rn;
ID4 DATE4 ID5 DATE5 Comment
---------- --------- ---------- --------- ---------------------
4 02-JAN-13 5 05-JAN-13 First set of 4 and 5
4 08-JAN-13 5 12-JAN-13 Second set of 4 and 5
我现在不确定你是否真的希望返回/显示'评论'......可能不会,这会略微简化它。
对于修改后的要求:
with t as (
select id, dt, lead(dt) over (partition by id order by dt) as next_dt
from t42
where id in (4, 5)
)
select t4.id as id4, t4.dt as date4, t5.id as id5, min(t5.dt) as date5
from t t4
join t t5 on t5.dt > t4.dt and (t4.next_dt is null or t5.dt <= t4.next_dt)
where t4.id = 4
and t5.id = 5
group by t4.id, t4.dt, t5.id
order by t4.dt;
ID4 DATE4 ID5 DATE5
---------- --------------------- ---------- ---------------------
4 16.03.2012 17:49:28 5 10.05.2012 09:38:56
4 12.06.2012 08:47:52 5 02.08.2012 11:27:43
4 03.08.2012 13:24:54 5 03.08.2012 14:14:07
CTE使用LEAD
来查看每个ID的下一个日期,这与ID为4时非常相关;如果没有额外的ID 4,那么它可以为null。然后,连接仅查找位于两个ID 4日期之间(或最后一个ID 4日期之后)的ID 5记录。如果您想在第一个结果中使用备用(稍后)ID 5日期,请使用MAX
而不是MIN
。 (我不是100%关于>
和<=
匹配;我试图解释你所说的内容,但如果它不是正确的话你可能需要调整一下。/ p>
要解决看起来像9i的错误(根据MOS可能在9.2.0.3或9.2.0.6中修复,但确实取决于你遇到的错误):
select t4.id as id4, t4.dt as date4, t5.id as id5, min(t5.dt) as date5
from (
select id, dt, lead(dt) over (partition by id order by dt) as next_dt
from t42
where id = 4
) t4
join (select id, dt
from t42
where id = 5
) t5 on t5.dt > t4.dt and (t4.next_dt is null or t5.dt <= t4.next_dt)
group by t4.id, t4.dt, t5.id
order by t4.dt;
不幸的是,我没有足够的旧版本来测试这个版本。您不必使用t5
子选择,您可以直接将主表连接到t4
,但我认为这有点清晰。
答案 1 :(得分:1)
你想要的很简单。只需根据ID对您的记录进行排名。
with ranked_data
as (select
id,
date_col,
row_number() over (partition by id order by date_col) as rnk
from your_table
where id in (4, 5))
select t4.id as id4, t4.date_col as date4, t5.id as id5, t5.date_col as date5
from ranked_data t4
full outer join ranked_data t5
on (t4.rnk=t5.rnk and t4.id=4 and t5.id=5)
答案 2 :(得分:0)
没有使用分析的自我加入就可以了:
SELECT distinct
first_value(id) over (partition by rk order by dt),
min(dt) over (partition by rk),
last_value(id) over (partition by rk order by dt rows between unbounded preceding and unbounded following) id5 ,
max(dt) over (partition by rk)
FROM (
SELECT id, dt, dense_rank() over (partition by id order by dt) rk
FROM t
where id in (4, 5)
)
这会找到与“第一个”日期对应的id值,因此如果4和5的日期顺序相反,那么您将在“4”列中显示5。目前尚不清楚这是否是你想要的。