使用此架构:
CREATE TABLE BAR (id INT PRIMARY KEY);
CREATE TABLE FOO (id INT PRIMARY KEY, rank INT UNIQUE, fk INT, FOREIGN KEY (fk) REFERENCES Bar(id));
INSERT INTO BAR (id) VALUES (1);
INSERT INTO BAR (id) VALUES (2);
-- sample values
INSERT INTO FOO (id, rank, fk) VALUES (1, 10, 1);
INSERT INTO FOO (id, rank, fk) VALUES (2, 3, 1);
INSERT INTO FOO (id, rank, fk) VALUES (3, 9, 2);
INSERT INTO FOO (id, rank, fk) VALUES (4, 5, 1);
INSERT INTO FOO (id, rank, fk) VALUES (5, 12, 1);
INSERT INTO FOO (id, rank, fk) VALUES (6, 14, 2);
如何查询FOO
和的某些行,这些行与BAR
的同一行相关联,排在rank
的下一行?也就是说,我想搜索某些行(“目标”),并且对于每个目标行,我还想找到另一行(“辅助”),这样辅助具有secondary.fk = target.fk
的所有行的最高等级和 secondary.rank < target.rank
。
例如,如果我定位所有行(没有where子句),我会期望这个结果:
TARGET_ID TARGET_RANK SECONDARY_ID SECONDARY_RANK
--------- ----------- ------------ --------------
1 10 4 5
2 3 NULL NULL
3 9 NULL NULL
4 5 2 3
5 12 1 10
6 14 3 9
当目标行有id
2或3时,没有辅助行,因为没有行与目标行具有相同的fk
和较低的rank
。
我试过了:
SELECT F1.id AS TARGET_ID, F1.rank as TARGET_RANK, F2.id AS SECONDARY_ID, F2.rank AS SECONDARY_RANK
FROM FOO F1
LEFT JOIN FOO F2 ON F2.rank = (SELECT MAX(S.rank)
FROM FOO S
WHERE S.fk = F1.fk
AND S.rank < F1.rank);
...但我得到ORA-01799: a column may not be outer-joined to a subquery
。
接下来我尝试了这个:
SELECT F1.id AS TARGET_ID, F1.rank AS TARGET_RANK, F2.id AS SECONDARY_ID, F2.rank AS SECONDARY_RANK
FROM FOO F1
LEFT JOIN (SELECT S1.rank, S1.fk
FROM FOO S1
WHERE S1.rank = (SELECT MAX(S2.rank)
FROM FOO S2
WHERE S2.rank < F1.rank
AND S2.fk = F1.fk)
) F2 ON F2.fk = F1.fk;
...但我得到ORA-00904: "F1"."FK": invalid identifier
。
肯定有一些方式在单个查询中执行此操作?
答案 0 :(得分:1)
它不喜欢临时表中的子查询。诀窍是连接所有次要行,rank
小于目标的rank
,然后使用WHERE子句过滤除最大值以外的所有行,同时确保不过滤掉没有辅助的目标行
select F1.id as TARGET_ID, F1.rank as TARGET_RANK, F2.id as SECOND_ID, F2.rank as SECOND_RANK
from FOO F1
left join FOO F2 on F1.fk = F2.fk and F2.rank < F1.rank
where F2.rank is null or F2.rank = (select max(S.rank)
from FOO S
where S.fk = F1.fk
and S.rank < F1.rank);
答案 1 :(得分:0)
select id,
lead(rank) over (partition by fk order by rank) next_rank
lag(rank) over (partition by fk order by rank) prev_rank
from foo
它比自联接更有效。
但是如果你想折磨你的数据库,你可以尝试
select id,
(select min(f2.rank) from foo f2 where f2.fk = f1.fk and f2.rank >f1.rank) next_rank,
(select max(f2.rank) from foo f2 where f2.fk = f1.fk and f2.rank <f1.rank) prev_rank
from foo f1
好的,我误解了输出中需要的东西。这是一个例子:
select id, rank, prev_rank_id from (
select id, rank,
lag(id) over (partition by fk order by rank) prev_rank_id
from foo
)
where id in (1, 3)
Analitic函数正在处理OUTPUT数据集。您需要将其包装到另一个select语句中以限制实际输出。
答案 2 :(得分:0)
select f1.rank f1rank, f2.rank as f2rank
from foo f1
left join foo f2 on f1.fk = f2.fk and f1.rank > f2.rank
这将为每个foo记录返回一行,该记录在同一个表中有另一条记录(使用fk确定)并且低于现有的等级。现在你只需要那里的max(f2.rank)。将上方转入子查询并找到最大值
Select f1rank, max(f2rank) f2rank
from
(select f1.rank f1rank, f2.rank as f2rank
from foo f1
left join foo f2 on f1.fk = f2.fk and f1.rank > f2.rank) a
group by f1rank
抱歉,我没有时间测试/排除故障,但逻辑应该在那里。