SQL查询-连接多对多关系,有选择地筛选/连接

SQL查询-连接多对多关系,有选择地筛选/连接,sql,join,db2,many-to-many,Sql,Join,Db2,Many To Many,我发现自己在使用SQL查询时遇到了一些不可行的情况,我希望我错过了一些东西,或者可能学到了一些新的东西。我正在使用的DB2数据库的结构并不是为这种查询而构建的,但我的任务是 假设我们有餐桌人员和餐桌组。组可以包含多个人,一个人可以是多个组的一部分。是的,已经很乱了。在任何情况下,都有两个中间表将两者链接起来。问题是我需要从组列表开始,获取这些组中的所有人,然后获取这些人所属的所有组,这将是初始组集的超集。这意味着从小组开始,加入到人们中,然后再回到小组中,再次加入到小组中。我还需要来自结果集中两

我发现自己在使用SQL查询时遇到了一些不可行的情况,我希望我错过了一些东西,或者可能学到了一些新的东西。我正在使用的DB2数据库的结构并不是为这种查询而构建的,但我的任务是


假设我们有餐桌人员和餐桌组。组可以包含多个人,一个人可以是多个组的一部分。是的,已经很乱了。在任何情况下,都有两个中间表将两者链接起来。问题是我需要从组列表开始,获取这些组中的所有人,然后获取这些人所属的所有组,这将是初始组集的超集。这意味着从小组开始,加入到人们中,然后再回到小组中,再次加入到小组中。我还需要来自结果集中两个表的信息,因此排除了许多技术

为了获得更多信息,我不得不将其与许多其他表连接起来,查询变得庞大、繁琐且缓慢。我想知道是否有某种方法可以从人开始,将其加入到组中,然后指定如果一个人在提供的组集中有一个组(通过子查询完成),那么应该返回该人的所有组。我不知道如何实现这一点,但我想(希望)有一种相对干净的方法可以在SQL中实现这一点

一个快速而肮脏的例子:

SELECT ...
FROM GROUPS g
  JOIN LINKING_A a 
     ON g.GROUPID = a.GROUPID
        AND GROUPID IN (subquery)
  JOIN LINKING_B b 
     ON a.GROUPLIST = b.GROUPLIST
  JOIN PEOPLE p 
     ON b.PERSONID = p.PERSONID
    --This gets me all people affiliated with groups, 
    -- but now I need all groups affiliated with those people...
  JOIN LINKING_B b2 
     ON p.PERSONID = b2.PERSONID
  JOIN LINKING_A a2 
     ON b2.GROUPLIST = a.GROUPLIST
  JOIN GROUPS g2
     ON a2.GROUPID = g.GROUPID

然后我可以从结果集中的p和g2返回信息。你可以看出我哪里有麻烦。在一些大型表上有很多连接,更不用说在这个查询中执行的许多其他连接了。我需要能够通过将人员加入组来进行查询,然后指定如果任何人员在子查询中有关联的组,则应返回与人员中该条目关联的所有组。我想分组讨论可能正是这个问题,但我还没有充分利用这个问题来真正了解情况。因此,如果Bill是组A、B和C的一部分,并且我们的子查询返回一个包含组A的集合,那么结果集应该包括Bill以及组A、B和C。

以下是获取所提供组列表中的所有组的较短方法。这有用吗

Select g.*
From Linking_B b
   Join Linking_B b2
      On b2.PersonId = b.PersonId
   Join Group g
      On g.GroupId = b2.GroupId
Where b.Groupid in (SubQuery)

我不清楚为什么同时有Linking_A和Linking_B。通常,表示两个主表之间的多对多关系所需的只是一个带有GroupID和PersonId的关联表

我经常建议使用“公共表表达式”[CTE],以帮助您将问题分解为更容易理解的块。CTE是使用WITH子句指定的,该子句可以在启动主SELECT查询之前包含多个CTE

我将假设您想要开始的组列表是由您的子查询指定的,因此这将是第一个CTE。下一个选择属于这些群体的人。然后,查询的最后一部分选择这些人所属的组,并从两个主表返回列

WITH g1 as
(subquery)
, p1 as
(SELECT p.*
   from g1
   join Linking a1  on g1.groupID=a1.groupID
   join People  p   on p.personID=a1.personID )
SELECT p1.*, g2.*
  from p1
  join Linking a2   on p2.personID=a2.personID
  join Groups  g2   on  g2.groupID=a2.groupID

我想我应该先建立一个你想要获取记录的人的列表,然后用它来查询这些人的所有组。这将适用于任何数量的链接表,并添加适当的联接:

with persons_wanted as
(
     --figure out which people are in a group you want to include
     select p.person_key
     from person p
     join link l1
     on p.person_key = l1.person_key
     join groups g
     on l1.group_key = g.group_key
     where g.group name in ('GROUP_I_WANT_PEOPLE_FROM', 'THIS_ONE_TOO')
     group by p.person_key --we only want each person_key once
)
--now pull all the groups for the list of people in at least one group we want
select p.name as person_name, g.name as group_name, ...
from person p
join link l1
on p.person_key = l1.person_key
join groups g
on l1.group_key = g.group_key
where p.person_key in (select person_key from persons_wanted);

也许我做得不对,但它不起作用。有两个链接表,对其中一个进行自连接并从中拆分并不会返回所有组,只返回子查询中的人员和组。问题是我需要避免两次遍历这些链接表。当我这样做的时候,查询的成本会变得太高。考虑到您希望做的事情,我看不到任何方法可以避免这一点。WITH子句仍然可能有帮助,因为它会将您的人员列表移动到临时表中,并且只执行一次初始联接。如果做不到这一点,您是否考虑过使用包含人员列表的临时表或物化查询,并对其运行一个更简单的查询以拉出组列表?不过,这并不能避免两次跨链接表连接的成本。由于与此特定查询不相关的附加数据的规范化,存在多个链接表。您几乎没有选择两次连接链接表,因为问题的基本性质涉及两个级别的关联-属于特定组的所有人,然后这些人所属的所有团体。无论如何,您必须在某个点遍历每个层的链接信息。我们讨论的每个表的行数是多少?您工作的绩效要求是什么,或者有什么特殊问题?组的起始集是静态的,还是可能会更改?