您可以运行所有这些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=7Mship=8行中看到它。
Bobby和Sally都在Bridge俱乐部,因此Sally被确定为Bobby的Bridge Club会员的赞助商。
Sally不是编织俱乐部的成员,因此Bobby的Knitting Club成员身份并未显示Sally是赞助者。


抱歉,安装时间太长。这是我的实际问题:


如何确定缺少赞助的地方?
在示例中,我们有Mship=5Mship=6行。
约翰是罗德的赞助商。
我们可以看到Rod游泳俱乐部会员资格的赞助。
Rod和John都是针织俱乐部的成员,
但是Rod并未将John证明为他的Knitting Club会员资格的赞助商。
这是不正确的,这就是我所追求的。
我想查询所有这些缺少的赞助。


我可以使用游标/ 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




致力于创建此查询使我想到可以优化数据库设计。当前的模型将很难保持一致性:您的问题本身就证明了这一点。将来,如果赞助商在他的一位赞助人已经参加的新俱乐部注册,会发生什么?再一次,您将需要检测丢失的sponshorship关系,并以某种方式创建它。

实际上,赞助商和赞助商之间存在1-1的关系,因为您声明赞助应该涵盖所有共享成员身份。看起来您似乎不会允许赞助商拥有多个赞助商,即使在不同的俱乐部也是如此。

我建议您删除sponshorship表,并将直接保存给发起人的自外部密钥存储在成员表中。从这里开始,很容易检查两个成员共有哪些俱乐部,并使用SQL查询正确分配会费。

关于sql - 识别关系不一致的记录,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54754812/

10-11 00:06