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