簡體   English   中英

復雜的SQL Join幫助!

[英]Complex SQL Join help!

(有關快速回顧,請參見標題為DATA的部分。只能在圖A和圖B中獲得結果,我想要的是所需的結果,請嘗試在答案部分中發布的所有內容。)

總而言之,我一直在努力從我的應用程序中聰明地開始使用聯接。 男孩花了我一段時間,但我想我已經掌握了這個主意,但是我無法使該查詢正常工作。

請幫我! 這是按原樣的聯接:

SELECT     TOP (100) PERCENT a.Id, a.DateCreated, a.DateModified, a.LastUpdatedBy, a.AccomplishmentTypeId, a.Title, a.Description, a.ApplicableDate, 
                  a.LocalId, at.Name AS AccomplishmentTypeName, a.Name AS AreaName, u.FirstName, u.LastName, ug.Name AS UserGroupName, 
                  ugo.Name AS OtherUserGroupName
FROM         dbo.Accomplishment AS a INNER JOIN
                  dbo.AccomplishmentType AS at ON at.Id = a.AccomplishmentTypeId INNER JOIN
                  dbo.AccomplishmentArea AS aal ON aal.AccomplishmentId = a.Id INNER JOIN
                  dbo.Area AS al ON al.Id = aal.AreaId INNER JOIN
                  dbo.UserAccomplishment AS ua ON ua.AccomplishmentId = a.Id INNER JOIN
                  dbo.[User] AS u ON u.Id = ua.UserId INNER JOIN
                  dbo.UserUserGroup AS uug ON uug.UserId = u.Id INNER JOIN
                  dbo.UserGroup AS ug ON ug.Id = uug.UserGroupId INNER JOIN
                  dbo.UserGroupType AS ugt ON ugt.Id = ug.UserGroupTypeId INNER JOIN
                  dbo.UserUserGroup AS uugo ON uugo.UserId = u.Id LEFT OUTER JOIN
                  dbo.UserGroup AS ugo ON ugo.Id = uugo.UserGroupId LEFT OUTER JOIN
                  dbo.UserGroupType AS ugto ON ugto.Id = ugo.UserGroupTypeId
WHERE     (ug.LocalId = 2) AND (ugo.LocalId <> 2) AND (ugto.LocalId = 4)
ORDER BY a.DateCreated DESC, u.LastName, u.FirstName, u.Id, UserGroupName

現在,這有點復雜,但是我正在做的是從所有相關表中選擇一項有成就的信息,其中有一個與之相關聯的用戶,而該用戶的用戶組的localId = 2,但是如果確實有,我還想返回該用戶所在的所有用戶組,其中usertype.localid = 4。

讓我給出一些示例數據來希望使這一點變得清楚,現在我在數據庫中有3個如下所示的成就:

- - - -(數據)

Accomplishment 1:
   User: John
      Usergroups: Group A (Of UserGroupType 2), Group B (Of UserGroupType 3), 
                  Group C (Of UserGroupType 4), Group D (Of UsergroupType 4)
Accomplishment 2:
   User: John
      Usergroups: Group A (Of UserGroupType 2), Group B (Of UserGroupType 3), 
                  Group C (Of UserGroupType 4), Group D (Of UsergroupType 4)
Accomplishment 3:
   User: Sue
      Usergroups: Group A (Of UserGroupType 2)

現在我上面的Join結果4行:

-------(圖A):

 Accomplishment 1, John, Group A, Group C
 Accomplishment 1, John, Group A, Group D
 Accomplishment 2, John, Group A, Group C
 Accomplishment 2, John, Group A, Group D

現在,這是正確的,因為該用戶擁有的每個userGroup都有一行,其usergrouptype.localid為4,但是,如何使其顯示完成3? 我首先將所有聯接作為內部聯接開始,然后認為進行最后的幾個左聯接將使它返回用戶,即使它沒有用戶組類型為localid 4的用戶組,也沒有。 基本上,我希望它返回組A中用戶的任何成就,並且如果他們具有usergrouptype 4的任何用戶組,則也返回所有這些用戶組。

有什么想法嗎? 如果我不清楚,請告訴我,這太復雜了,我可能還沒有足夠的解釋。

編輯:

(有關快速回顧,請參見標題為DATA的部分。只能在圖A和圖B中獲得結果,我想要的是所需的結果,請嘗試在答案部分中發布的所有內容。)

HLGEM和Tom Hs的結果都相同,雖然更接近我的需求,但仍然相差甚遠。 現在,在圖B中我得到9個結果。

-------(圖B):

Accomplishment 1, John, Group A, Group C
Accomplishment 1, John, Group A, Group D
Accomplishment 1, John, Group A, Null
Accomplishment 1, John, Group A, Group B (Group B is UsergroupType 3)
Accomplishment 3, Sue, Group A, Null
Accomplishment 2, John, Group A, Group C
Accomplishment 2, John, Group A, Group D
Accomplishment 2, John, Group A, Null
Accomplishment 2, John, Group A, Group B (Group B is UsergroupType 3)

因此,出於某種原因,即使John的用戶組的用戶組類型為4,該行也包含空行,並且其中包含組B的行的用戶組類型為3,因此不應顯示該行。

再次編輯:

(有關快速回顧,請參見標題為DATA的部分。只能在圖A和圖B中獲得結果,我想要的是所需的結果,請嘗試在答案部分中發布的所有內容。)

是的,我確實為此感到困惑,我已經嘗試了將東西放在where子句中的幾乎每一種組合,它要么是4行沒有成就3,要么是9行,其中用戶John每個成就又獲得了2行,或者6行沒有完成3和usergrouptype 3用戶組的額外行。 更令人困惑的是,在最后一行添加ugto.localid = 4似乎對結果沒有任何影響。 它向我顯示了一個用戶組,該用戶組的用戶組類型為3,在查詢的任何地方都看不到。

編輯5/02/10

(有關快速回顧,請參見標題為DATA的部分。只能在圖A和圖B中獲得結果,我想要的是所需的結果,請嘗試在答案部分中發布的所有內容。)

我認為我希望它的設置是不可能的嗎? 無論如何,我想要的結果是這5行:

-------(所需結果):

Accomplishment 1, John, Group A, Group C
Accomplishment 1, John, Group A, Group D
Accomplishment 2, John, Group A, Group C
Accomplishment 2, John, Group A, Group D
Accomplishment 3, Sue, Group A, Null

這是我嘗試過的所有內容及其提供的結果的列表:(請原諒糟糕的SSMS格式)

以下所有內容均基於此基本查詢:

開始查詢/嘗試1:

SELECT     TOP (100) PERCENT a.Id, a.DateCreated, a.DateModified, a.LastUpdatedBy, a.AccomplishmentTypeId, a.Title, a.Description, a.ApplicableDate, 
                  a.LocalId, at.Name AS AccomplishmentTypeName, al.Name AS AreaName, u.FirstName, u.LastName, ug.Name AS UserGroupName, 
                  ugo.Name AS OtherUsergroupName
  FROM         dbo.Accomplishment AS a INNER JOIN
                  dbo.AccomplishmentType AS at ON at.Id = a.AccomplishmentTypeId INNER    JOIN
                  dbo.AccomplishmentArea AS aal ON aal.AccomplishmentId = a.Id INNER JOIN
                  dbo.Area AS al ON al.Id = aal.AreaId INNER JOIN
                  dbo.UserAccomplishment AS ua ON ua.AccomplishmentId = a.Id INNER JOIN
                  dbo.[User] AS u ON u.Id = ua.UserId INNER JOIN
                  dbo.UserUserGroup AS uug ON uug.UserId = u.Id INNER JOIN
                  dbo.UserGroup AS ug ON ug.Id = uug.UserGroupId INNER JOIN
                  dbo.UserGroupType AS ugt ON ugt.Id = ug.UserGroupTypeId INNER JOIN
                  dbo.UserUserGroup AS uugo ON uugo.UserId = u.Id LEFT OUTER JOIN
                  dbo.UserGroup AS ugo ON ugo.Id = uugo.UserGroupId AND ugo.LocalId <> 2 LEFT OUTER JOIN
                  dbo.UserGroupType AS ugto ON ugto.Id = ugo.UserGroupTypeId AND ugto.LocalId = 4
 WHERE     (ug.LocalId = 2)
 ORDER BY a.DateCreated DESC, u.LastName, u.FirstName, u.Id, UserGroupName

結果: 圖B (請參見上面的方法) 為什么不好:出現 John的Null並顯示類型3的用戶組。

嘗試2:

嘗試1,減去所有的內聯聯接篩選(仍然在最后兩個聯接上保持左聯接)和以下where語句:

WHERE (ug.LocalId = 2)
  AND (ugo.LocalId <> 2 OR ugo.LocalId is null)
  AND (ugto.LocalId = 4 OR ugto.LocalId is null) 

結果: 圖A (請參見上面的方法) 不好的原因:不包括成就3

嘗試3:

與嘗試1相同,但在此行下開始更改:

 dbo.[User] AS u ON u.Id = ua.UserId INNER JOIN

在該行下的更改:

                  dbo.UserUserGroup AS uug ON uug.UserId = u.Id INNER JOIN
                  dbo.UserGroup AS ug ON ug.Id = uug.UserGroupId AND ug.LocalId = 2 INNER JOIN
                  dbo.UserGroupType AS ugt ON ugt.Id = ug.UserGroupTypeId INNER JOIN
                  dbo.UserUserGroup AS uugo ON uugo.UserId = u.Id LEFT OUTER JOIN
                  dbo.UserGroup AS ugo ON ugo.Id = uugo.UserGroupId AND ugo.LocalId <> 2 LEFT OUTER JOIN
                  dbo.UserGroupType AS ugto ON ugto.Id = ugo.UserGroupTypeId
WHERE     (ugto.LocalId = 4)
ORDER BY a.DateCreated DESC, u.LastName, u.FirstName, u.Id, UserGroupName

(有關快速回顧,請參見標題為DATA的部分。只能在圖A和圖B中獲得結果,我想要的是所需的結果,請嘗試在答案部分中發布的所有內容。)

@ChaosPandion關於重新格式化的評論是一個好主意,但是也許您需要一些幫助來了解什么是好的格式。 好吧,對於每個人來說,它可能都不同:-),但是如果我正在編寫查詢,我將其格式設置如下:

SELECT  TOP (100) PERCENT
          a.Id,
          a.DateCreated,
          a.DateModified,
          a.LastUpdatedBy,
          a.AccomplishmentTypeId,
          a.Title,
          a.Description,
          a.ApplicableDate,  
          a.LocalId,
          at.Name AS AccomplishmentTypeName,
          a.Name AS AreaName,
          u.FirstName,
          u.LastName,
          ug.Name AS UserGroupName,  
          ugo.Name AS OtherUserGroupName 
FROM dbo.Accomplishment AS a
INNER JOIN dbo.AccomplishmentType AS at
  ON at.Id = a.AccomplishmentTypeId
INNER JOIN dbo.AccomplishmentArea AS aal
  ON aal.AccomplishmentId = a.Id
INNER JOIN dbo.Area AS al
  ON al.Id = aal.AreaId
INNER JOIN dbo.UserAccomplishment AS ua
  ON ua.AccomplishmentId = a.Id
INNER JOIN dbo.[User] AS u
  ON u.Id = ua.UserId
INNER JOIN dbo.UserUserGroup AS uug
  ON uug.UserId = u.Id
INNER JOIN dbo.UserGroup AS ug
  ON ug.Id = uug.UserGroupId
INNER JOIN dbo.UserGroupType AS ugt
  ON ugt.Id = ug.UserGroupTypeId
INNER JOIN dbo.UserUserGroup AS uugo
  ON uugo.UserId = u.Id
LEFT OUTER JOIN dbo.UserGroup AS ugo
  ON ugo.Id = uugo.UserGroupId
LEFT OUTER JOIN dbo.UserGroupType AS ugto
  ON ugto.Id = ugo.UserGroupTypeId 
WHERE ug.LocalId = 2 AND
      ugo.LocalId <> 2 AND
      ugto.LocalId = 4
ORDER BY a.DateCreated DESC,
         u.LastName,
         u.FirstName,
         u.Id,
         UserGroupName

我認為這種格式使其更易於閱讀。

分享並享受。

我不確定我是否完全了解您要執行的操作,但是我認為您需要將標准移至“左外部聯接”中。 如果將其放在WHERE子句中,則如果LEFT OUTER JOIN未找到匹配項,則這些列將顯示為NULL,因此它們將無法通過WHERE子句檢查。 您實際上是在將“左外部連接”轉換為“內部連接”。

FROM
    dbo.Accomplishment AS a
INNER JOIN dbo.AccomplishmentType AS at ON
    at.Id = a.AccomplishmentTypeId
INNER JOIN dbo.AccomplishmentArea AS aal ON
    aal.AccomplishmentId = a.Id
INNER JOIN dbo.Area AS al ON
    al.Id = aal.AreaId
INNER JOIN dbo.UserAccomplishment AS ua ON
    ua.AccomplishmentId = a.Id
INNER JOIN dbo.[User] AS u ON
    u.Id = ua.UserId
INNER JOIN dbo.UserUserGroup AS uug ON
    uug.UserId = u.Id
INNER JOIN dbo.UserGroup AS ug ON
    ug.Id = uug.UserGroupId AND
    ug.localid = 2
INNER JOIN dbo.UserGroupType AS ugt ON
    ugt.Id = ug.UserGroupTypeId
INNER JOIN dbo.UserUserGroup AS uugo ON
    uugo.UserId = u.Id
LEFT OUTER JOIN dbo.UserGroup AS ugo ON
    ugo.Id = uugo.UserGroupId AND
    ugo.localid <> 2
LEFT OUTER JOIN dbo.UserGroupType AS ugto ON
    ugto.Id = ugo.UserGroupTypeId
WHERE
    ugto.localid = 4
ORDER BY
    a.DateCreated DESC, u.LastName, u.FirstName, u.Id, UserGroupName

在學習左聯接時,您犯了一個經典錯誤,您在where子句中放置了將其變為內部聯接的條件

嘗試這個

SELECT     a.Id, a.DateCreated, a.DateModified, a.LastUpdatedBy, a.AccomplishmentTypeId, a.Title,
a.Description, a.ApplicableDate,  a.LocalId, at.Name AS AccomplishmentTypeName, 
a.Name AS AreaName, u.FirstName, u.LastName, ug.Name AS UserGroupName, ugo.Name AS OtherUserGroupName 
FROM        dbo.Accomplishment AS a 
INNER JOIN  dbo.AccomplishmentType AS at ON at.Id = a.AccomplishmentTypeId 
INNER JOIN  dbo.AccomplishmentArea AS aal ON aal.AccomplishmentId = a.Id 
INNER JOIN  dbo.Area AS al ON al.Id = aal.AreaId 
INNER JOIN  dbo.UserAccomplishment AS ua ON ua.AccomplishmentId = a.Id 
INNER JOIN  dbo.[User] AS u ON u.Id = ua.UserId 
INNER JOIN  dbo.UserUserGroup AS uug ON uug.UserId = u.Id 
INNER JOIN  dbo.UserGroup AS ug ON ug.Id = uug.UserGroupId 
INNER JOIN  dbo.UserGroupType AS ugt ON ugt.Id = ug.UserGroupTypeId 
INNER JOIN  dbo.UserUserGroup AS uugo ON uugo.UserId = u.Id 
LEFT OUTER JOIN  dbo.UserGroup AS ugo ON ugo.Id = uugo.UserGroupId  AND ugo.LocalId <> 2
LEFT OUTER JOIN  dbo.UserGroupType AS ugto ON ugto.Id = ugo.UserGroupTypeId  AND ugto.LocalId = 4
WHERE     ug.LocalId = 2 
ORDER BY a.DateCreated DESC, u.LastName, u.FirstName, u.Id, UserGroupName 

請參閱此鏈接以獲取對此的解釋: http : //wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN

到目前為止,這是我重寫的內容:

SELECT a.Id, a.DateCreated, a.DateModified, a.LastUpdatedBy, a.AccomplishmentTypeId, 
       a.Title, a.Description, a.ApplicableDate, a.LocalId, 
       at.Name AS AccomplishmentTypeName, a.Name AS AreaName, u.FirstName, 
       u.LastName, ug.Name AS UserGroupName, ugo.Name AS OtherUserGroupName
  FROM dbo.Accomplishment a 
  JOIN dbo.AccomplishmentType AS at ON at.Id = a.AccomplishmentTypeId 
  JOIN dbo.AccomplishmentArea AS aal ON aal.AccomplishmentId = a.Id 
  JOIN dbo.Area AS al ON al.Id = aal.AreaId 
  JOIN dbo.UserAccomplishment AS ua ON ua.AccomplishmentId = a.Id 
  JOIN dbo.[User] AS u ON u.Id = ua.UserId 
  JOIN dbo.UserUserGroup AS uug ON uug.UserId = u.Id 
  JOIN dbo.UserGroupType AS ugt ON ugt.Id = ug.UserGroupTypeId 
  JOIN dbo.UserGroup AS ug ON ug.Id = uug.UserGroupId 
  JOIN dbo.UserGroupType AS ugto ON ugto.Id = ug.UserGroupTypeId
 ORDER BY a.DateCreated DESC, u.LastName, u.FirstName, u.Id, UserGroupName

您有一個到UserUserGroup的多余UserUserGroup ,並且可以合並到UserGroup的聯接,因為LEFT JOIN條件將取消上一次聯接到同一表的操作。

您的聯接都很好。 這是過濾!

如果編寫的過濾器不允許左連接表中的空值,那么您的過濾器將刪除左連接允許的其他記錄。

ugo和ugto均可通過LEFT JOIN到達

WHERE (ug.LocalId = 2)
  AND (ugo.LocalId <> 2 OR ugo.LocalId is null)
  AND (ugto.LocalId = 4 OR ugto.LocalId is null) 

PS-混合JOIN和FILTERING標准(在ON或在WHERE中都使用)是導致精神錯亂的秘訣。 保持理智!


編輯:在連接中發現錯誤:

INNER JOIN dbo.UserUserGroup AS uugo ON uugo.UserId = u.Id

應該

LEFT JOIN dbo.UserUserGroup AS uugo ON uugo.UserId = u.Id

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM