下面的SQL包含一些DDL和一个简单的查询。
我得到的结果是
a1|b1|c1
a1|b2|c3
a3|b3|c2
a3|b3|c3
a3|b3|c4
a3|b3|c5
a3|b5|c6
a3|b5|c7
我想要的结果是
a1 |b1 |c1
a1 |b2 |c3
a3 |b3 |c2
null |null |c4
null |null |c5
a3 |b5 |c6
null |null |c7
我尝试使用MAX,MIN,rownums等等。我没办法。我只包括我开始使用的基本查询而不是我尝试的所有选项,因为它们根本不起作用。任何帮助表示赞赏!
BEGIN TRANSACTION;
drop table if exists table_A;
drop table if exists table_B;
drop table if exists table_C;
/* Create a table called NAMES */
CREATE TABLE table_A(a_Id text PRIMARY KEY, val_a text);
CREATE TABLE table_B(a_Id text, b_Id text, val_b text);
CREATE TABLE table_C(b_Id text, c_Id text, val_c text);
/* Create few records in this table */
INSERT INTO table_A VALUES('a1','va1');
INSERT INTO table_A VALUES('a2','va2');
INSERT INTO table_A VALUES('a3','va3');
INSERT INTO table_B VALUES('a1', 'b1','vb1');
INSERT INTO table_B VALUES('a1', 'b2','vb2');
INSERT INTO table_B VALUES('a3', 'b3','vb31');
INSERT INTO table_B VALUES('a2', 'b4','vb4');
INSERT INTO table_B VALUES('a3', 'b5','vb31');
INSERT INTO table_C VALUES('b1', 'c1','vc1');
INSERT INTO table_C VALUES('b3', 'c2','vc2');
INSERT INTO table_C VALUES('b3', 'c3','vc3');
INSERT INTO table_C VALUES('b2', 'c3','vc3');
INSERT INTO table_C VALUES('b3', 'c4','vc2');
INSERT INTO table_C VALUES('b3', 'c5','vc3');
INSERT INTO table_C VALUES('b5', 'c6','vc3');
INSERT INTO table_C VALUES('b5', 'c7','vc3');
COMMIT;
select
a.a_Id, b.b_Id, c.c_Id
from
table_A as a
join
table_B as b
on a.a_Id = b.a_Id
join
table_C as c
on b.b_Id = c.b_Id;
答案 0 :(得分:1)
我首先建议你在演示逻辑中处理这个听起来更好。但是,可以单独使用SQL来完成。
您可以利用Oracle的LAG()
函数和CASE
来检查上一行是否具有相同的a和b id值。
以下是使用公用表表达式的示例:
with cte as (
select
a.a_Id, b.b_Id, c.c_Id,
lag (a.a_Id,1) over (order by a.a_Id, b.b_Id) prev_a_Id,
lag (b.b_Id,1) over (order by a.a_Id, b.b_Id) prev_b_Id
from table_A a
join table_B b
on a.a_Id = b.a_Id
join table_C c
on b.b_Id = c.b_Id
order by
a.a_id, b.b_id
)
select
case
when prev_a_Id is null or
prev_a_Id <> a_Id or
prev_b_Id <> b_Id
then a_id
end new_a_Id,
case
when prev_a_Id is null or
prev_a_Id = a_Id or
prev_b_Id = b_Id
then b_id
end new_b_Id, c_Id
from cte;
答案 1 :(得分:1)
这样的事情应该有用(我已经在PostgreSql上测试了它,也应该在Oracle上工作)
SELECT
case when row_number = 1 then a_id end as a_id,
case when row_number = 1 then b_id end as b_id,
c_id
FROM (
SELECT
a.a_Id,
b.b_Id,
c.c_Id,
row_number() OVER (partition by a.a_id, b.b_id order by c.c_id) as row_number, --for a_id, b_id
row_number() OVER (partition by c.c_id order by c.c_id) as row_number2 --to avoid c_id duplicates
FROM
table_A a
join
table_B b on a.a_Id = b.a_Id
join table_C c on b.b_Id = c.b_Id
) innerquery
WHERE
row_number2 = 1 --this is to avoid c_id duplicates
答案 2 :(得分:1)
select t1.a_id, t1.b_id, table_c.c_id
from table_c
left join
(
select a_Id, b_Id, c_Id
from
(
select a.a_Id as a_id, b.b_Id as b_id, c.c_Id as c_id,
ROW_NUMBER() OVER (PARTITION BY a.a_ID, b.b_id ORDER BY C_ID) as aNum
from table_A as a
join table_B as b on a.a_Id = b.a_Id
join table_C as c on b.b_Id = c.b_Id
) t2
where aNum = 1
) t1 on table_c.c_id = t1.c_id
order by table_c.c_id
小提琴:
答案 3 :(得分:0)
我不认为我完全明白你想要实现,但如果我错了,请纠正我。
首先,您使用内部联接来连接表(至少如果您使用的是sql server,但在oracle中应该是相同的)。这意味着,例如,只有在第二个表中有对应行的情况下才会从第一个表中获取行,而如果现在第二个表中对应行的第一个表中的行,则第二个表中的行永远不会出现在结果中。
根据您想要实现的结果描述,您需要的是外部联接。哪一个左/右/全外连接取决于您尝试实现的(看起来您需要左外连接或全外连接)。我不太确定你的目标是什么,因为你解释了这个具体例子中的数据应该看起来不是一般情况。
因此,请查看不同联接类型的说明,然后选择sql join types
还有一个输入注释:文本类型可能是我认为是主键的列表中的最后一种类型。