SQL Server可选连接

时间:2009-12-09 12:41:05

标签: sql sql-server join

我有几张桌子(确切地说,7张)我互相交叉加入。这部分给了我一些问题;

表格“操作”

 -----------------------------------------
| ID | Package ID | Action Type | Message |
 -----------------------------------------
| 40 | 100340     | 0           | OK      |
| 41 | 100340     | 12          | Error   |
| 42 | 100340     | 2           | OK      |

| 43 | 100341     | 4           | OK      |
| 44 | 100341     | 0           | Error   |
| 45 | 100341     | 12          | OK      |
 -----------------------------------------

表格“套餐”

 ----------------------
| ID     | Name        |
 ----------------------
| 100340 | Testpackage |
| 100341 | Package xy  |
 ----------------------

我完成了交叉连接,但是当Package中没有指定ID的Actions时,该包上的所有操作都完全丢失,而不仅仅是Name空白 - 这就是我想要的。

因此,如果缺少引用,只需将相应的连接列留空或作为空字符串......:

 ----------------------------------------------------------------------
| Package ID | Name        | Action 0 | Action 2 | Action 4 | Action 12 |
 ----------------------------------------------------------------------
| 100340     | Testpackage | OK       | OK       |          | Error     |
| 100341     | Package xy  | Error    |          | OK       | OK        |
 ----------------------------------------------------------------------

这怎么可能?

修改

抱歉,我刚看到我的示例完全错误,我更新了它最终应该是什么样子。

我当前的查询看起来像这样(如上所述,只是一个提取,因为实际的查询大约是三倍,包括更多的表)

SELECT
 PackageTable.ID AS PackageID,
 PackageTable.Name,
 Action0Table.Message  AS Action0,
 Action2Table.Message  AS Action2,
 Action4Table.Message  AS Action4,
 Action12Table.Message AS Action12
FROM
 Packages AS PackageTable LEFT OUTER JOIN
  Actions AS Action0Table ON PackageTable.ID  = Action0Table.PackageID LEFT OUTER JOIN
  Actions AS Action2Table ON PackageTable.ID  = Action2Table.PackageID LEFT OUTER JOIN
  Actions AS Action4Table ON PackageTable.ID  = Action4Table.PackageID LEFT OUTER JOIN
  Actions AS Action12Table ON PackageTable.ID = Action12Table.PackageID
WHERE
 Action0Table.ActionType  = 0 AND
 Action2Table.ActionType  = 2 AND
 Action4Table.ActionType  = 4 AND
 Action12Table.ActionType = 12

6 个答案:

答案 0 :(得分:5)

那么为什么你不能只做一个外部的JOIN,例如:

SELECT  `Package ID`, Name, `Action Type`, `Action Date`
   FROM Actions
   LEFT OUTER JOIN Packages
   ON Actions.`Package ID` = Packages.`Package ID`

答案 1 :(得分:4)

你有'where'条款,不包括遗失的行动记录吗?即使您使用外部联接,仍然会应用您的where子句,如果它们不匹配,则不会包含操作记录。

编辑:问题是你的ActionType过滤器。如果没有匹配的操作记录,则ActionType为null,与您的任何过滤器都不匹配。因此,您可以在where子句中添加“或ActionType为null”。我不知道您的业务需求,但这可能包含超出您想要的记录。

答案 2 :(得分:2)

正如其他人所说,我也有同样的答案。

只是显示不同的结果

declare @Actions table(id int , packageid int, actiontype int,dt date)
declare @Packages table(id int,name varchar(50))
insert into @Actions 
    select 40,100340,0,'2009/01/01 3:00pm' union all
    select 41,100340,12,'2009/01/01 5:00pm' union all
    select 42,100340,2,'2009/01/01 5:30pm' union all
    select 43,100341, 4,'2009/01/02 8:00am'
insert into @Packages 
    select 100340,'Testpackage'

左外连接查询

select a.packageid,p.name,a.actiontype,a.dt
from @Actions a
left join @Packages p
on a.packageid = p.id

完全加入(在这种情况下,您将获得相同的结果)

select a.packageid,p.name,a.actiontype,a.dt
from @Actions a
full join @Packages p
on a.packageid = p.id

输出:

packageid   name    actiontype  dt
100340  Testpackage 0   2009-01-01
100340  Testpackage 12  2009-01-01
100340  Testpackage 2   2009-01-01
100341  NULL    4   2009-01-02

内部联接查询(您不想要)

select a.packageid,p.name,a.actiontype,a.dt
from @Actions a
join @Packages p
on a.packageid = p.id

<强>输出:

packageid   name    actiontype  dt
100340  Testpackage 0   2009-01-01
100340  Testpackage 12  2009-01-01
100340  Testpackage 2   2009-01-01

答案 3 :(得分:2)

您将离开(外部)加入包裹表。这意味着如果记录不在packages表中(连接条件左侧的表),则不要将其包含在最终结果中。

您可以在动作表上进行正确(外部)联接,在这种情况下,您将获得所有动作记录,无论它们是否在包表中匹配。

你可以做一个完整的(外部)联接,换句话说,给我两个表中的所有记录。

最后,你可以进行内连接,或两个表中都有的记录。

您可能会发现在此处绘制维恩图是有帮助的,左侧表格为左侧圆圈,右侧表格为右侧圆圈。因此,内连接表示图的重叠区域。

因此,要回答您的问题,您将需要调整您的联接以进行完全外连接或正确连接,具体取决于您是否要查看没有操作的包。并且你将需要调整你的where子句以包括许多其他海报所建议的空行动。虽然您可能希望向其中添加一个附加子句,其中表达式排除所有操作都为空的记录。另外,在编写示例时,您只会看到包中的操作为0,2,4和12的包;根据您提供的信息,这听起来不正确。

SELECT
 PackageTable.ID AS PackageID,
 PackageTable.Name,
 Action0Table.Message  AS Action0,
 Action2Table.Message  AS Action2,
 Action4Table.Message  AS Action4,
 Action12Table.Message AS Action12
FROM
 Packages AS PackageTable
  RIGHT OUTER JOIN Actions AS Action0Table ON 
     PackageTable.ID  = Action0Table.PackageID
  RIGHT OUTER JOIN Actions AS Action2Table ON
     PackageTable.ID  = Action2Table.PackageID
  RIGHT OUTER JOIN Actions AS Action4Table ON
     PackageTable.ID  = Action4Table.PackageID
  RIGHT OUTER JOIN Actions AS Action12Table ON
     PackageTable.ID = Action12Table.PackageID
WHERE
 (Action0Table.ActionType  = 0 OR Action0Table.ActionType IS NULL) AND
 (Action2Table.ActionType  = 2 OR Action2Table.ActionType IS NULL) AND
 (Action4Table.ActionType  = 4 OR Action4Table.ActionType IS NULL) AND
 (Action12Table.ActionType = 12 OR Action12Table.ActionType IS NULL) AND
 NOT (Action0Table.ActionType IS NULL AND Action2Table.ActionType IS NULL AND
  Action4Table.ActionType IS NULL AND Action12Table.ActionType IS NULL)

如果要查看没有任何这些操作的包,则需要删除该最终的NOT子句。此外,根据数据的质量,一旦开始包含空值,您可能会开始接收重复记录;在这种情况下,你的问题变得更难解决,你需要回到我们身边。

答案 4 :(得分:1)

阅读'外部联接'

答案 5 :(得分:1)

而不是INNER JOIN使用LEFT JOIN。这将成为.-