【问题标题】:SQL Server optional joinsSQL Server 可选联接
【发布时间】:2009-12-09 12:41:05
【问题描述】:

我有几个表(确切地说是 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 并在Actions 中指定ID 时,该包上的所有操作都完全丢失,而不仅仅是留下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

【问题讨论】:

  • 请注意,您使用的不是CROSS JOINS,而是LEFT OUTER JOINS。

标签: sql sql-server join


【解决方案1】:

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

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

?

【讨论】:

  • 我这样做是因为我认为它必须起作用,但没有成功。问题是,正如我所说,我使用 7 个表加入一个表,但不知何故,它没有进行正确的连接,我想可能是因为我误解了外部连接:-/
【解决方案2】:

您是否有排除缺失操作记录的“where”子句?即使您使用外连接,仍将应用您的 where 子句,并且如果它们不匹配,则不会包含操作记录。

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

【讨论】:

  • 我刚刚更新了这一点,因为我一开始就忘记了 - 我想错误在那里是正确的,但是如何摆脱它以获得我需要的结果呢?
  • 像这样: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为空)AND(Action12Table.ActionType = 12 或 Action12Table.ActionType 为空)
【解决方案3】:

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

只是向你展示不同的结果

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

【讨论】:

    【解决方案4】:

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

    您可以对操作表进行右(外)连接,在这种情况下,您将获得所有操作记录,无论它们在包表中是否匹配。

    您可以进行完全(外部)联接,换句话说,将两个表中的所有记录都给我。

    最后你可以做一个内连接,或者两个表中都存在的记录。

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

    因此,要回答您的问题,您需要将联接调整为完全外部联接或右联接,具体取决于您是否希望查看没有操作的包。并且您将需要调整您的 where 子句以包含许多其他海报所建议的空操作。尽管您可能希望在 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 子句。此外,根据数据的质量,一旦您开始包含空值,您可能会开始收到重复记录;在这种情况下,您的问题将变得更加难以解决,您需要与我们联系。

    【讨论】:

      【解决方案5】:

      阅读“外部连接”

      【讨论】:

        【解决方案6】:

        使用 LEFT JOIN 代替 INNER JOIN。这样就可以了。-

        【讨论】:

          猜你喜欢
          • 2017-01-01
          • 2017-04-27
          • 2019-05-31
          • 1970-01-01
          • 1970-01-01
          • 2011-08-15
          • 1970-01-01
          • 2023-03-29
          • 2017-08-14
          相关资源
          最近更新 更多