我正在使用隔离的源代码并尝试创建衍生表查询,该查询通过特殊字符标识标头并将标头与其列表项匹配。我的目标是将最终结果纳入Oracle的视图。
我从用户生成的单个表开始:
TASK_ID TASK_NAME
1 ******HEADER 1******
2 TASK A
3 TASK B
4 TASK C
5 ******HEADER 2******
6 TASK D
7 TASK E
8 ******HEADER 3******
9 TASK F
10 TASK G
11 ******HEADER 4******
12 TASK H
13 TASK I
14 TASK J
我把它分解为两个派生表:
A.TASK_ID A.TASK_NAME
1 ******HEADER 1******
5 ******HEADER 2******
8 ******HEADER 3******
11 ******HEADER 4******
B.TASK_ID B.TASK_NAME
2 TASK A
3 TASK B
4 TASK C
6 TASK D
7 TASK E
9 TASK F
10 TASK G
12 TASK H
13 TASK I
14 TASK J
但是我被困在试图来到这里:
A.TASK_ID A.TASK_NAME B.TASK_ID B.TASK_NAME
1 ******HEADER 1****** 2 TASK A
1 ******HEADER 1****** 3 TASK B
1 ******HEADER 1****** 4 TASK C
5 ******HEADER 2****** 6 TASK D
5 ******HEADER 2****** 7 TASK E
8 ******HEADER 3****** 9 TASK D
8 ******HEADER 3****** 10 TASK E
11 ******HEADER 4****** 12 TASK H
11 ******HEADER 4****** 13 TASK I
11 ******HEADER 4****** 14 TASK J
如果我使用'Where'或'Between'命令编写一个小于或大于的SQL,则标题会捕获意外的任务。
所以我不知道该怎么做。如果我必须编写一个程序,我不知道我是如何对PL / SQL新手的。我知道C#和VB以及其他编程,但我不确定我的方法是否错误。
非常感谢任何指导!
答案 0 :(得分:4)
假设标题和其他任务总是按照您显示的顺序排序 - 因为否则我看不到您如何建立任何其他关系 - 并且您始终以标题开头,然后您可以将标题应用于标题你使用an analytic function like row_number()
:
select task_id, task_name,
row_number() over (order by task_id) as rnk
from tasks
where task_name like '***%';
TASK_ID TASK_NAME RNK
---------- -------------------- ----------
1 ******HEADER 1****** 1
5 ******HEADER 2****** 2
8 ******HEADER 3****** 3
11 ******HEADER 4****** 4
你可以对非标题记录做同样的事情;但是这里的排名是他们的原始订单(包括标题)之间的差异,以及一旦删除它们之后:
select task_id, task_name, orig_rnk,
row_number() over (order by task_id) as new_rnk,
orig_rnk - row_number() over (order by task_id) as rnk
from (
select task_id, task_name, row_number() over (order by task_id) as orig_rnk
from tasks
)
where task_name not like '***%';
TASK_ID TASK_NAME ORIG_RNK NEW_RNK RNK
---------- -------------------- ---------- ---------- ----------
2 TASK A 2 1 1
3 TASK B 3 2 1
4 TASK C 4 3 1
6 TASK D 6 4 2
7 TASK E 7 5 2
9 TASK F 9 6 3
10 TASK G 10 7 3
12 TASK H 12 8 4
13 TASK I 13 9 4
14 TASK J 14 10 4
然后你可以使用该排名加入这两个列表:
with a as (
select task_id, task_name, row_number() over (order by task_id) as rnk
from tasks
where task_name like '***%'
),
b as (
select task_id, task_name,
orig_rnk - row_number() over (order by task_id) as rnk
from (
select task_id, task_name, row_number() over (order by task_id) as orig_rnk
from tasks
)
where task_name not like '***%'
)
select a.task_id, a.task_name, b.task_id, b.task_name
from a
join b on b.rnk = a.rnk
order by a.task_id, b.task_id;
TASK_ID TASK_NAME TASK_ID TASK_NAME
---------- -------------------- ---------- --------------------
1 ******HEADER 1****** 2 TASK A
1 ******HEADER 1****** 3 TASK B
1 ******HEADER 1****** 4 TASK C
5 ******HEADER 2****** 6 TASK D
5 ******HEADER 2****** 7 TASK E
8 ******HEADER 3****** 9 TASK F
8 ******HEADER 3****** 10 TASK G
11 ******HEADER 4****** 12 TASK H
11 ******HEADER 4****** 13 TASK I
11 ******HEADER 4****** 14 TASK J
答案 1 :(得分:3)
与Alex Poole(并做出相同的假设)一样,我倾向于使用分析函数来解决这个问题。但是,对我来说,这似乎是lead
的一个很好的候选人:
select task_id, task_name,
lead(task_id) over (order by task_id) as next_task_id
from tasks
where task_name like '***%';
TASK_ID TASK_NAME NEXT_TASK_ID
---------- -------------------- ------------
1 ******HEADER 1****** 5
5 ******HEADER 2****** 8
8 ******HEADER 3****** 11
11 ******HEADER 4******
使用这些数据,下一步变得相当简单:
with a as (
select task_id, task_name, lead(task_id) over (order by task_id) as next_task_id
from tasks
where task_name like '***%'
),
b as (
select task_id, task_name
from tasks
where task_name not like '***%'
)
select a.task_id, a.task_name, b.task_id, b.task_name
from a
join b on b.task_id between a.task_id and coalesce(a.next_task_id,b.task_id)
order by a.task_id, b.task_id;
答案 2 :(得分:2)
以下是一些基于您最初发布的数据的解决方案 - 希望您可以根据您的特定数据集适当修改它们。 (我已经包含了两个,因为最终可能会比另一个表现得更好,但我无法说出哪些因为我没有完整的数据集!):
(这个第一个例子最初以更复杂的方式计算了header_id,但Alex Poole指出它可以像查找header_name一样完成。我已经更新它以使用Alex'的建议,因为它明显优越!)
with sample_data as (select 1 task_id, '******HEADER 1******' task_name from dual union all
select 2 task_id, 'TASK A' task_name from dual union all
select 3 task_id, 'TASK B' task_name from dual union all
select 4 task_id, 'TASK C' task_name from dual union all
select 5 task_id, '******HEADER 2******' task_name from dual union all
select 6 task_id, 'TASK D' task_name from dual union all
select 7 task_id, 'TASK E' task_name from dual union all
select 8 task_id, '******HEADER 3******' task_name from dual union all
select 9 task_id, 'TASK F' task_name from dual union all
select 10 task_id, 'TASK G' task_name from dual union all
select 11 task_id, '******HEADER 4******' task_name from dual union all
select 12 task_id, 'TASK H' task_name from dual union all
select 13 task_id, 'TASK I' task_name from dual union all
select 14 task_id, 'TASK J' task_name from dual),
res as (select task_id,
last_value(case when task_name like '*%' then task_id end ignore nulls) over (order by task_id) header_id,
last_value(case when task_name like '*%' then task_name end ignore nulls) over (order by task_id) header_name,
case when task_name not like '*%' then task_name end task_name
from sample_data)
select header_id,
header_name,
task_id,
task_name
from res
where header_id != task_id
order by header_id, task_id;
HEADER_ID HEADER_NAME TASK_ID TASK_NAME
---------- -------------------- ---------- --------------------
1 ******HEADER 1****** 2 TASK A
1 ******HEADER 1****** 3 TASK B
1 ******HEADER 1****** 4 TASK C
5 ******HEADER 2****** 6 TASK D
5 ******HEADER 2****** 7 TASK E
8 ******HEADER 3****** 9 TASK F
8 ******HEADER 3****** 10 TASK G
11 ******HEADER 4****** 12 TASK H
11 ******HEADER 4****** 13 TASK I
11 ******HEADER 4****** 14 TASK J
with sample_data as (select 1 task_id, '******HEADER 1******' task_name from dual union all
select 2 task_id, 'TASK A' task_name from dual union all
select 3 task_id, 'TASK B' task_name from dual union all
select 4 task_id, 'TASK C' task_name from dual union all
select 5 task_id, '******HEADER 2******' task_name from dual union all
select 6 task_id, 'TASK D' task_name from dual union all
select 7 task_id, 'TASK E' task_name from dual union all
select 8 task_id, '******HEADER 3******' task_name from dual union all
select 9 task_id, 'TASK F' task_name from dual union all
select 10 task_id, 'TASK G' task_name from dual union all
select 11 task_id, '******HEADER 4******' task_name from dual union all
select 12 task_id, 'TASK H' task_name from dual union all
select 13 task_id, 'TASK I' task_name from dual union all
select 14 task_id, 'TASK J' task_name from dual),
hdr as (select task_id hdr_id,
task_name hdr_name
from sample_data
where task_name like '*%'),
tsk as (select task_id,
last_value(case when task_name like '*%' then task_name end ignore nulls) over (order by task_id) header_name,
case when task_name not like '*%' then task_name end task_name
from sample_data)
select hdr.hdr_id,
hdr.hdr_name,
tsk.task_id,
tsk.task_name
from hdr
inner join tsk
on (hdr.hdr_name = tsk.header_name
and hdr.hdr_id != tsk.task_id)
order by hdr.hdr_id, tsk.task_id;
HDR_ID HDR_NAME TASK_ID TASK_NAME
---------- -------------------- ---------- --------------------
1 ******HEADER 1****** 2 TASK A
1 ******HEADER 1****** 3 TASK B
1 ******HEADER 1****** 4 TASK C
5 ******HEADER 2****** 6 TASK D
5 ******HEADER 2****** 7 TASK E
8 ******HEADER 3****** 9 TASK F
8 ******HEADER 3****** 10 TASK G
11 ******HEADER 4****** 12 TASK H
11 ******HEADER 4****** 13 TASK I
11 ******HEADER 4****** 14 TASK J