左外连接通过链接表,使用min()将连接限制为一行

时间:2017-09-27 19:52:49

标签: oracle left-join outer-join

我正在尝试编写一个Oracle SQL查询来连接两个通过链接表链接的表(我的意思是一个包含2列的表,每个表都是主表的外键)。 min()函数用于将左外连接的结果限制为单行。

我的模特由"父母和#34;和"侄子"。父母可以有0个或更多的侄子。可以启用或禁用父母。每个侄子都有一个生日。我的查询的目标是:

为每个已启用的父级打印一行,列出父级最老的侄子(即带有分钟(生日)的侄子)。

我的问题在这里通过sqlfiddle来说明:http://sqlfiddle.com/#!4/9a3be0d/1

我可以为已启用的父母列出所有侄子的查询,但这还不够好 - 我只希望每个父母一行,其中只包含年龄侄子。将where子句形成外表似乎是我的绊脚石。

我的表格和示例数据:

create table parent (parent_id number primary key, parent_name varchar2(50), enabled int);
create table nephew  (nephew_id number primary key, birthday date, nephew_name varchar2(50));
create table parent_nephew_link  (parent_id number not null, nephew_id number not null);

parent table:
+----+-------------+---------+
| id | parent_name | enabled |
+----+-------------+---------+
| 1  | Donald      | 1       |
+----+-------------+---------+
| 2  | Minnie      | 0       |
+----+-------------+---------+
| 3  | Mickey      | 1       |
+----+-------------+---------+
  nephew table:
  +-----------+------------+-------------+
  | nephew_id | birthday   | nephew_name |
  +-----------+------------+-------------+
  | 100       | 01/01/2017 | Huey        |
  +-----------+------------+-------------+
  | 101       | 01/01/2016 | Dewey       |
  +-----------+------------+-------------+
  | 102       | 01/01/2015 | Louie       |
  +-----------+------------+-------------+
  | 103       | 01/01/2014 | Morty       |
  +-----------+------------+-------------+
  | 104       | 01/01/2013 | Ferdie      |
  +-----------+------------+-------------+
parent_nephew_link table:
+-----------+-----------+
| parent_id | nephew_id |
+-----------+-----------+
| 1         | 100       |
+-----------+-----------+
| 1         | 101       |
+-----------+-----------+
| 1         | 102       |
+-----------+-----------+
| 3         | 103       |
+-----------+-----------+
| 3         | 104       |
+-----------+-----------+

我的(不正确)查询:

-- This query is not right, it returns a row for each nephew
select parent_name, nephew_name
from parent p
left outer join parent_nephew_link pnl
  on p.parent_id = pnl.parent_id
left outer join nephew n
  on n.nephew_id = pnl.nephew_id
where enabled = 1
--    I wish I could add this clause to restrict the result to the oldest 
--    nephew but p.parent_id is not available in sub-selects.
--    You get an ORA-00904 error if you try this:
-- and n.birthday = (select min(birthday) from nephew nested where nested.parent_id = p.parent_id)

我想要的输出是:

+-------------+-------------+
| parent_name | nephew_name |
+-------------+-------------+
| Donald      | Louie       |
+-------------+-------------+
| Mickey      | Ferdie      |
+-------------+-------------+

感谢您的任何建议! 约翰

markaaronky的建议

我尝试过使用markaaronky的建议,但这个sql也存在缺陷。

-- This query is not right either, it returns the correct data but only for one parent
select * from (
  select parent_name, n.nephew_name, n.birthday
  from parent p
  left outer join parent_nephew_link pnl
    on p.parent_id = pnl.parent_id
  left outer join nephew n
    on n.nephew_id = pnl.nephew_id
  where enabled = 1
  order by parent_name, n.birthday asc
) where rownum <= 1

2 个答案:

答案 0 :(得分:0)

为什么不: (1)在SELECT语句中包含来自nephews表的n.birthday (2)在您的查询中添加ORDER BY n.birthday ASC (3)还修改你的选择,使它只占用顶行?

我试着在sqlfiddle中为你写这个,但它似乎不喜欢表别名(例如,当我写n.birthday时它会抛出错误),但我确信这在Oracle中是合法的,即使我是一个SQL Server人。

另外,如果我没记错,Oracle没有像SQL Server那样的SELECT TOP ......你必须做一些类似“WHERE ROWNUM = 1”的事情吗?同样的概念......你只是订购你的结果,所以最老的侄子是第一排,而你只是第一排。

也许一个不受欢迎的副作用是你将获得生日以及结果中的名字。如果这是不可接受的,我道歉。看起来你的问题暂时没有答案,这个解决方案至少应该给你一个开始。

最后,由于您的生日列上没有NOT NULL约束并且正在执行左外连接,因此可以通过添加AND n.birthday IS NOT NOT来使查询更安全

答案 1 :(得分:0)

使用:

select parent_name, nephew_name
from parent p
left outer join
(
  SELECT pnl.parent_id, n.nephew_name
    FROM parent_nephew_link pnl
    join nephew n
    on n.nephew_id = pnl.nephew_id
    AND n.BIRTHDAY = ( 
        SELECT min( BIRTHDAY ) 
        FROM nephew n1
        JOIN parent_nephew_link pnl1
        ON pnl1.NEPHEW_ID = n1.NEPHEW_ID
        WHERE pnl1.PARENT_ID = pnl.PARENT_ID
    )
) ppp
on p.parent_id = ppp.parent_id
where p.enabled = 1

演示:http://sqlfiddle.com/#!4/98758/23

| PARENT_NAME | NEPHEW_NAME |
|-------------|-------------|
|      Mickey |       Louie |
|      Donald |      Ferdie |