[英]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.