2013-02-08 61 views
0

Folks, 所有我期望的是扩展INNER JOIN。让我谈谈点。我有两个表部门& Emp。一个部门可以有多个Emp的&而不是其他方式。SQL INNER JOIN仅在第一次匹配时返回父行值

 
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 

希望我传达了我想要的东西。它只是一个常规的内部加入的外键约束。但是,我希望第一个表(Dept)中的值是NULL-ed,除了第一个匹配。话虽如此,我不在乎第一场比赛是什么。请看下面 - 只是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. 

在此先感谢。尽管它是一个简单的例子,但对于很长的解释抱歉。

+0

你会尝试左连接吗? – DevelopmentIsMyPassion 2013-02-08 17:24:25

+2

左连接不会得到他们正在寻找的结果。看起来更像他们试图对结果进行分组,并且只允许Dept_id和Dept_name中每个部门的第一个匹配的值。我很好奇你为什么要这么做,因为这会让数据显示吉尔吉姆和贾瑞特没有任何部门。正确的做法是获得所有列中的值,并处理代码中用于显示结果的格式。随着所要求的内容,如果你改变客户端上的排序,你将有不可读的数据 – TimWagaman 2013-02-08 17:29:16

+0

你是对的。这是一个疯狂的查询。我正在尝试做一个我的应用程序应该做的部分。但是,我确信有一种方法可以通过查询来完成并且想知道这一点。感谢评论。 – Yogi 2013-02-08 17:51:56

回答

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 
+0

我想这是针对某种“ASCII报告” – 2013-02-08 17:35:02

+0

@a_horse_with_no_name我想可能会出现这种情况,这确实是最好的办法! – 2013-02-08 17:37:26

+0

这就是我想要的。感谢Bassam。 – Yogi 2013-02-08 17:57:10

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

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 
0

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

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" 
0

,因为我想不出你会想,其他则报告的目的,那么你也可以通过使用SQL * Plus formmating这样做的一个原因。

在SQL *查询加

break on dept_id skip 1 

享受之前只需要运行下面的命令。