sql – 识别关系不一致的记录

您可以运行所有这些SQL并查看结果
here.

>跳过结果和随之而来的问题来解决问题.

我有一张俱乐部的桌子(一个俱乐部,如一群人或一群人,如“游泳俱乐部”或“针织俱乐部”).

DECLARE @club TABLE (
   Id INT
   ,Name NVARCHAR(255)
   );
INSERT INTO @club VALUES
   (1, 'Swim Club')
   ,(2, 'Knitting Club')
   ,(3, 'Bridge Club');

我有一张会员表.

DECLARE @member TABLE (
   Id INT
   ,Name NVARCHAR(255)
   );
INSERT INTO @member VALUES
   (1, 'John Jones')
   ,(2, 'Sally Smith')
   ,(3, 'Rod Roosevelt')
   ,(4, 'Bobby Burns')
   ,(5, 'Megan Moore');

会员可以属于许多俱乐部,因此有一个会员表将俱乐部与会员联系起来(并且还描述了会员费的价格).

DECLARE @membership TABLE (
   Id INT
   ,Member INT --FK to @member
   ,Club INT --FK to @club
   ,Dues INT --the cost of membership
   );
INSERT INTO @membership VALUES
   (1,1,1,10)
   ,(2,1,2,5)
   ,(3,2,1,10)
   ,(4,2,3,20)
   ,(5,3,1,10)
   ,(6,3,2,5)
   ,(7,4,2,5)
   ,(8,4,3,20)
   ,(9,5,1,10)
   ,(10,5,3,20);

大多数会员只需支付相关的会费.但是,有些会员是由其他会员赞助的.因此,这些赞助会员的会费将由另一位会员(赞助商)支付.因此,我们有一个赞助表.赞助表将赞助商(支付会费)连接到特定俱乐部的Sponsee(由赞助商支付其会费).由于赞助是针对俱乐部的,因此赞助记录连接两个会员记录而不是两个会员记录.

DECLARE @sponsorship TABLE (
   Id INT
   ,Sponsee_Membership INT --FK to Sponsee's @membership record
   ,Sponsor_Membership INT --FK to Sponsor's @membership record
   );
INSERT INTO @sponsorship VALUES
   (1,5,1)
   ,(2,8,4)
   ,(3,9,3)
   ,(4,10,4);

要全面了解我们的俱乐部/会员/赞助商,我们有:

SELECT
    mship.Id AS 'Mship'
    ,mem.Name AS 'Member'
    ,c.Name AS 'Club'
    ,mship.Dues
    ,spons_mem.Name AS 'Sponsor'
FROM
    @membership AS mship
    JOIN @member AS mem
        ON mship.Member = mem.Id
    JOIN @club AS c
        ON mship.Club = c.Id
    LEFT JOIN @sponsorship AS spons
        ON spons.Sponsee_Membership = mship.Id
    LEFT JOIN @membership AS spons_mship
        ON spons_mship.Id = spons.Sponsor_Membership
    LEFT JOIN @member AS spons_mem
        ON spons_mem.Id = spons_mship.Member;

这给了我们这些结果:

Mship   Member        Club         Dues  Sponsor
  1   John Jones     Swim Club      10    NULL
  2   John Jones     Knitting Club   5    NULL
  3   Sally Smith    Swim Club      10    NULL
  4   Sally Smith    Bridge Club    20    NULL
  5   Rod Roosevelt  Swim Club      10    John Jones
  6   Rod Roosevelt  Knitting Club   5    NULL
  7   Bobby Burns    Knitting Club   5    NULL
  8   Bobby Burns    Bridge Club    20    Sally Smith
  9   Megan Moore    Swim Club      10    Sally Smith
 10   Megan Moore    Bridge Club    20    Sally Smith

赞助商应该涵盖所有共享会员资格.

>也就是说,如果Sally赞助Bobby,那么无论何时他们都在同一个俱乐部,Sally都会被认定为Bobby的赞助商.
>我们可以在Mship = 7和Mship = 8的行中看到这一点.
> Bobby和Sally都在Bridge Club,因此Sally被认定为Bobby的Bridge Club会员资格的赞助商.
>莎莉不是针织俱乐部的成员,所以鲍比的针织俱乐部会员资格并不表示莎莉是赞助商.

很抱歉长时间安装.这是我的实际问题:

>我如何确定缺少赞助的位置?
从示例中,我们有Mship = 5和Mship = 6.
>约翰是罗德的赞助商.
>我们可以看到Rod’s Swim Club会员资格的赞助.
>罗德和约翰也是针织俱乐部的成员,
>但Rod并未将约翰视为其针织俱乐部会员的赞助商.
>这是不正确的,这就是我所追求的.
>我想查询所有这些缺失的赞助商.

我可以使用游标/ WHILE循环来实现这一点,但我知道这样的解决方案通常不会采用适当的基于集合的方法.对此的正确查询是什么样的?
非常感谢.

最佳答案 这是一个可能响应您的要求的SQL查询.

逻辑是使用子查询基于映射member.id而不是memberships.id来生成赞助者和赞助者之间的映射;为此,我们使用聚合.然后,外部查询搜索赞助商和赞助商都参与的俱乐部,但赞助表中没有宣布任何关系

该查询返回每个违规成员的一条记录,包括赞助商和赞助商名称.

SELECT mship1.Id, m1.Name Member, m2.Name Sponsor, c.Name Club, mship1.Dues
FROM 
    @membership mship1
    INNER JOIN @club c ON c.Id = mship1.Club
    INNER JOIN (
        SELECT ms1.Member Sponsee_Member , MAX(ms2.Member) Sponsor_Member
        FROM @sponsorship ss
        INNER JOIN @membership ms1 ON ms1.Id = Sponsee_Membership
        INNER JOIN @membership ms2 ON ms2.Id = Sponsor_Membership
        GROUP BY ms1.Member
    ) rels ON rels.Sponsee_Member = mship1.Member
    INNER JOIN @membership mship2 ON mship2.Member = rels.Sponsor_Member AND mship2.Club = mship1.Club
    INNER JOIN @member m1 ON m1.Id = mship1.Member
    INNER JOIN @member m2 ON m2.Id = mship2.Member
    LEFT JOIN @sponsorship sship  ON sship.Sponsor_Membership = mship2.Id
WHERE sship.Id IS NULL
;

the rextester that you provided,这将返回:

Id   | Member          | Sponsor      | Club           | Dues
-----|-----------------|--------------|----------------|-----
6    | Rod Roosevelt   | John Jones   | Knitting Club  | 5

在创建此查询时,我认为您可以优化数据库设计.当前模型将难以保持一致性:您的问题本身就证明了这一点.将来,如果赞助商在新俱乐部注册,他的一个赞助商已经参加了会议,会发生什么?您将再次需要检测缺少的赞助关系,并以某种方式创建它.

你实际上赞助商和赞助商之间存在1-1关系,因为你说赞助商应该涵盖所有共享会员资格.看起来你不会允许赞助商拥有几个赞助商,即使是在不同的俱乐部.

我建议你放弃赞助表并直接在会员表中将赞助商的自我外键存储起来.从那里开始,很容易检查两个成员共有哪些俱乐部,并使用SQL查询正确分配会费.

点赞