SQL INNER JOIN仅在第一次匹配时返回父行值

时间:2013-02-08 17:22:04

标签: sql oracle

民间,       我正在寻找的是扩展INNER JOIN。让我谈谈这一点。我有两张桌子Dept& EMP。一个部门可以有多个Emp&不是相反。

Table Dept
Dept_id   Dept_Name
1         IT
2         HR
3         Other

Table Emp
Emp_id   Dept_id   Emp_Name
11       1         John
12       1         Jill
13       2         Jack
14       3         Jared
15       1         Jim
16       1         Jarret
17       2         Jacob

I need to JOIN it on Dept_id

Expected Results
Dept_id   Dept_name Emp_id   Emp_Name
1         IT        11       John
NULL      NULL      12       Jill
NULL      NULL      15       Jim
NULL      NULL      16       Jarret
2         HR        13       Jack
NULL      NULL      17       Jacob
3         Other     14       Jared
希望我能准确地传达我想要的东西。它只是外键约束的常规内部联接。但是,除了First Match之外,我希望第一个表(Dept)中的值为NULL。话虽这么说,我不在乎第一场比赛是什么。请参阅下面的内容 - 只是Dept_id 1的结果。

Expected Results (Only for Dept_id = 1)
It could be

Dept_id   Dept_name Emp_id   Emp_Name
1         IT        11       John
NULL      NULL      12       Jill
NULL      NULL      15       Jim
NULL      NULL      16       Jarret

OR

Dept_id   Dept_name Emp_id   Emp_Name
1         IT        15       Jim
NULL      NULL      12       Jill
NULL      NULL      11       John
NULL      NULL      16       Jarret

OR

Two other possibilities.

提前致谢。对于长篇解释很抱歉,即使它只是一个简单的案例。

6 个答案:

答案 0 :(得分:5)

我同意Ic。这是一个疯狂的查询似乎正在做你的应用程序应该做的事情,而不是你的SQL查询,说,写这些查询很有趣:)

SELECT CASE WHEN RowNumber = 1 THEN Dept_id ELSE NULL END AS Dept_id,
       CASE WHEN RowNumber = 1 THEN Dept_name ELSE NULL END AS Dept_name,
        Emp_id, Emp_Name
FROM Dept d
INNER JOIN 
(SELECT ROW_NUMBER() OVER (PARTITION BY Dept_id ORDER BY Emp_Name) AS RowNumber, 
       Dept_id, Dept_name, Emp_id, Emp_Name
FROM Emp ) t on t.Dept_id = d. Dept_id

答案 1 :(得分:1)

老实说,我不确定你为什么要这个结果。格式化通常最好留给UI层而不是数据库服务器。这样做会使数据看起来像每个部门的非首先员工实际上没有部门,并且从根本上打破了您在客户端可能具有的任何排序或编辑功能。

但是,您可以尝试:

SELECT FormattedDept.Dept_id, FormattedDept.Dept_Name, Emp.Emp_id, Emp.Emp_Name
FROM Emp
LEFT OUTER JOIN
(
    SELECT Dept.Dept_id, Dept.Dept_Name, MIN(Emp_id) AS Emp_id
    FROM Dept
    INNER JOIN Emp ON Dept.Dept_id = Emp.Dept_id
    GROUP BY Dept.Dept_id, Dept.Dept_Name
) FormattedDept ON Emp.Dept_id = FormattedDept.Dept_id
    AND Emp.Emp_id = FormattedDept.Emp_id
ORDER BY Emp.Dept_id, Emp.Emp_id

SQL Fiddle Demo

答案 2 :(得分:1)

select case
          when lag(d.dept_id) over (partition by d.dept_id order by e.emp_id) = d.dept_id then null
          else d.dept_id 
       end as dept_id,
       case
          when lag(d.dept_name) over (partition by d.dept_id order by e.emp_id) = d.dept_name then null
          else d.dept_name 
       end as dept_name,
       e.emp_id,
       e.emp_name
from dept d
  join emp e on e.dept_id = d.dept_id
order by d.dept_id, d.dept_name, e.emp_id

答案 3 :(得分:0)

正如我在上面的评论中提到的,我不确定你是否真的希望结果以你要求的方式返回。考虑一下。如果结果集已导出到Excel,并且用户更改了排序,那么您将丢失部门员工1-x所在的部门,而员工0仍将显示其部门。我建议您按Dept_id进行分组,而不是将dept_id和dept_name置空。在显示代码中处理该数据的显示。

答案 4 :(得分:0)

WITH newRecord
AS
(
   SELECT "Emp_id", "Dept_id", "Emp_Name",
           ROW_NUMBER() OVER (PARTITION BY "Dept_id" ORDER BY "Emp_id" ASC) RN
   FROM Emp  
)
SELECT  CASE WHEN RN = 1 THEN b."Dept_id" ELSE NULL END AS "Dept_ID",
        CASE WHEN RN = 1 THEN b."Dept_Name" ELSE NULL END AS "Dept_Name",
        "Emp_id", "Emp_Name"
FROM    newRecord a 
        INNER JOIN Dept b ON a."Dept_id" = b."Dept_id"

答案 5 :(得分:0)

因为我无法想到你想要其他报告目的的原因,那么你也可以通过使用SQL * Plus格式化做到这一点。

在SQL * Plus中的查询之前运行以下命令

break on dept_id skip 1

享受。