复杂的 SQL 连接帮助!

发布于 2024-09-08 05:38:10 字数 7250 浏览 8 评论 0原文

(为了快速回顾,请参阅标题为“数据”的部分。只能在图 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 项成就,看起来像这样:

--------(DATA)

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)

现在我上面的连接结果有 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,但是,我怎样才能使其也显示 Accomplishment 3??我首先将所有联接设为内部联接,然后认为制作最后几个左联接将处理它以返回用户,即使它没有 usergrouptype localid 4 的用户组,但事实并非如此。基本上,我希望它返回 A 组中的用户的任何成就,并且如果他们有任何用户组类型为 4 的用户组,也返回所有这些用户组。

有什么想法吗?如果我不清楚,请告诉我,这非常复杂,我可能解释得不够。

编辑:

(要快速回顾,请参阅标题为“数据”的部分。只能在图 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 的用户组,并且其中包含具有用户组类型 3 的组 B 的行,不应显示。

再次编辑:

(要快速回顾,请参阅标题为“数据”的部分。只能在图 A 和图 B 中获得结果,我想要的是所需的结果,尝试了答案部分中发布的所有内容。)

是的,我真的被这个难住了,我已经尝试了几乎所有在 where 子句中放入一些内容的组合,它要么是 4 行,没有成就 3,要么是 9 行,其中用户 John 每个成就获得额外的两行,或者是 6 行,没有成就完成 3 以及 usergrouptype 3 用户组的额外行。更令人困惑的是,在最后一行添加 ugto.localid = 4 似乎对结果没有任何影响。它显示了我的用户组,其用户组类型为 3,但我在查询中没有看到任何可以这样做的地方。

编辑 5/02/10

(要快速回顾,请参阅标题为“数据”的部分。只能在图 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

要快速回顾,请参阅标题为“数据”的部分只能得到图 A 和图 B 中的结果,我想要的是所需的结果,尝试了答案部分中发布的所有内容。)

(For a quick recap please see sections titled , DATA. Can only get results in FIGURE A, and FIGURE B, what I want is DESIRED RESULTS, tried everything posted in the answers section.)

All, I have been working hard to start smartly using joins in my application. Boy it took me a while but I think I am getting the hang of this, but I can't get this query to work.

Please help me! Here is the join as is:

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

Now this is kind of complex, but what I am doing is select info from all these related tables where there is an accomplishment, which has a user associated with it where that user has a usergroup localId = 2, but then if they do have that, I also want to return all the usergroups that user is in where the usertype.localid = 4.

Let me give some example data to hopefully make this clear, right now I have 3 accomplishments in the database that look like this:

-------(DATA)

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)

Now my above Join results 4 rows :

-------(FIGURE 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

Now this is correct insofar as there is a row for each userGroup the user has that has a usergrouptype.localid of 4, however, how can I make it so that it also displays Accomplishment 3?? I first started with all the joins being inner joins, and then thought making the last few left joins would take care of it to return the user even if it has no usergroups of usergrouptype localid 4, but it doesn't. Basically I want it to return any accomplishments of a user who is in group A, and if they have any usergroups that are of usergrouptype 4, return all those usergroups as well.

Any thoughts? And if I am not being clear please let me know, this is super complex and I may not have explained enough.

EDIT:

(For a quick recap please see sections titled , DATA. Can only get results in FIGURE A, and FIGURE B, what I want is DESIRED RESULTS, tried everything posted in the answers section.)

Both HLGEM and Tom H.s results are the same, and closer to what I need, but still off. Now I get 9 results in Figure B.

-------(FIGURE 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)

So for some reason it's including a null row for John even though he has usergroups that are of usergrouptype 4, and its including a row with group B which is of usergrouptype 3 and shouldn't be showing up.

EDIT AGAIN:

(For a quick recap please see sections titled , DATA. Can only get results in FIGURE A, and FIGURE B, what I want is DESIRED RESULTS, tried everything posted in the answers section.)

Yep I am truely stumped by this, I have tried pretty much every combination of putting some stuff in the where clause and it either is 4 rows without accomplishment 3, or 9 rows where user John gets two extra rows per accomplishment, or 6 Rows without accomplish 3 and an extra row for usergrouptype 3 usergroup. What's even more baffling is that adding the ugto.localid = 4 to the last line doesn't seem to have any affect on the results. It's showing my a usergroup which has usergrouptype 3 and I don't see anywhere in the query where that is okay.

EDIT 5/02/10

(For a quick recap please see sections titled , DATA. Can only get results in FIGURE A, and FIGURE B, what I want is DESIRED RESULTS, tried everything posted in the answers section.)

I think what I want my be impossible with how it's set up?? Anyway the result I want is these 5 rows:

-------(DESIRED RESULT):

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

Here is a list of everything I have tried and the results they give: (Please forgive the crappy SSMS formatting)

Everything below is based on this base query:

Starting Query/Attempt 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

Result: Figure B (See way above)
Why it's bad: Nulls for John show up and usergroup of type 3 is showing up.

Attempt 2:

Attempt 1, minus all in-line join filtering, (still keeping left joins on the last two) and the following where statement:

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

Result: Figure A (See way above)
Why it's bad: Doesn't include Accomplishment 3

Attempt 3:

Same as attempt 1 with changes starting underneath this line:

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

Changes under that line:

                  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

(For a quick recap please see sections titled , DATA. Can only get results in FIGURE A, and FIGURE B, what I want is DESIRED RESULTS, tried everything posted in the answers section.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

久随 2024-09-15 05:38:10

@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

我认为这种格式更易于阅读。

分享并享受。

@ChaosPandion's comment about reformatting is a good idea, but perhaps you need some help understanding what good formatting is. Well, it's probably different for everyone :-) but if I was writing your query I'd format it as follows:

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

I think this formatting makes it easier to read.

Share and enjoy.

随波逐流 2024-09-15 05:38:10

在学习左连接时,您犯了一个典型的错误,您在 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

You have made a classic mistake when learning left joins, you put conditions in the where clause that turn them into inner joins

Try this

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 

see this link for an explanation of this:
http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN

波浪屿的海角声 2024-09-15 05:38:10

我不确定我是否完全理解您想要做什么,但我认为您需要将您的标准转移到 LEFT OUTER JOIN 中。如果将其放入 WHERE 子句中,那么如果 LEFT OUTER JOIN 未找到匹配项,这些列将显示为 NULL,因此它们将无法通过 WHERE 子句检查。您实际上是将 LEFT OUTER JOIN 转变为 INNER JOIN。

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

I'm not sure that I completely understand what you're trying to do, but I think that you need to move your criteria into the LEFT OUTER JOINs. If you put it in the WHERE clause then if no match is found by the LEFT OUTER JOIN, those columns will appear as NULL and so they will fail the WHERE clause check. You are in effect turning the LEFT OUTER JOIN into an INNER JOIN.

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
锦欢 2024-09-15 05:38:10

这是我到目前为止重写的内容:

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 有一个冗余联接,并且您对 UserGroup 的联接可以合并,因为 LEFT JOIN 标准会取消在之前连接到同一个表时完成。

Here's what I re-wrote so far:

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

You've got a redundant join to UserUserGroup, and your joins to UserGroup can be consolidated because the LEFT JOIN criteria would cancel out what's done in the previous join to the same table.

给我一枪 2024-09-15 05:38:10

你加入一切都很好。这就是过滤!

如果您编写的过滤器不允许左连接表中存在空值,那么您的过滤器将删除左连接允许的其他记录。

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

You JOINs are all fine. It's the filtering!

If you write a filter that does not allow nulls in left joined tables, then your filter will remove the additional records that the left joins allow.

ugo and ugto are both reached by 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 - mixing JOIN and FILTERING criteria (both in ON or both in WHERE) is a recipe for insanity. Stay sane!


Edit: found an error in the join:

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

Should be

LEFT JOIN dbo.UserUserGroup AS uugo ON uugo.UserId = u.Id
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文