Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 识别关系不一致的记录_Sql_Sql Server_Tsql - Fatal编程技术网

Sql 识别关系不一致的记录

Sql 识别关系不一致的记录,sql,sql-server,tsql,Sql,Sql Server,Tsql,您可以运行所有这些SQL并查看结果 跳到结果和随后的问题,了解问题的实质。 我有一张俱乐部的桌子(一个团体或组织中的俱乐部,如“游泳俱乐部”或“编织俱乐部”) 我有一桌成员 DECLARE @member TABLE ( Id INT ,Name NVARCHAR(255) ); INSERT INTO @member VALUES (1, 'John Jones') ,(2, 'Sally Smith') ,(3, 'Rod Roosevelt')

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

  • 跳到结果和随后的问题,了解问题的实质。
我有一张俱乐部的桌子(一个团体或组织中的俱乐部,如“游泳俱乐部”或“编织俱乐部”)

我有一桌成员

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 @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都在桥牌俱乐部,因此Sally被认定为Bobby桥牌俱乐部会员的赞助商
  • 萨莉不是针织俱乐部的成员,因此鲍比的针织俱乐部会员资格并不表明萨莉是赞助商
很抱歉设置太长这是我的实际问题

  • 我如何确定缺少赞助的地方?
    从这个例子中,我们有行
    Mship=5
    Mship=6
  • 约翰是罗德的赞助商
  • 我们可以看到罗德游泳俱乐部会员的赞助
  • 罗德和约翰也是针织俱乐部的成员
  • 但是,罗德没有表示约翰是他的针织俱乐部会员的赞助商
  • 这是不正确的,这就是我所追求的
  • 我想查询所有这些缺少的赞助
我可以使用游标/WHILE循环来实现这一点,但我知道这样的解决方案通常不会采用正确的基于集合的方法。对此的正确查询是什么样的?
非常感谢。

这是一个SQL查询,可能会响应您的要求

逻辑是使用子查询,根据映射
member.id
,而不是
memberships.id
,在发起人和发起人之间生成映射;为此,我们使用聚合。然后,外部查询搜索赞助商和赞助商都参与的俱乐部,但在赞助表中没有声明其关系

查询将为每个有问题的成员返回一条记录,其中包含sponsee和赞助商名称

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
;
中,返回:

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

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

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


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

我发现我可以在一个查询中收集到这一点,方法是收集所有与CTE的赞助关系,找到所有应该有赞助的会员资格,然后使用EXCEPT删除所有现有赞助资格。我剩下的赞助应该存在,但不存在

WITH sponsored_relationships AS (
    SELECT DISTINCT
        sponsee_member.Id AS Sponsee
        ,sponsor_member.Id AS Sponsor
    FROM
        @sponsorship AS s
        JOIN @membership AS sponsee_mship
            ON s.Sponsee_Membership = sponsee_mship.Id
        JOIN @member AS sponsee_member
            ON sponsee_mship.Member = sponsee_member.Id
        JOIN @membership AS sponsor_mship
            ON s.Sponsor_Membership = sponsor_mship.Id
        JOIN @member AS sponsor_member
            ON sponsor_mship.Member = sponsor_member.Id
    )
SELECT
    see_mem.Name AS Sponsee
    ,sor_mem.Name AS Sponsor
    ,c.Name AS Club
FROM
    sponsored_relationships AS sr
    JOIN @member AS see_mem
        ON sr.Sponsee = see_mem.Id
    JOIN @membership AS see_mship
        ON see_mship.Member = see_mem.Id
    JOIN @member AS sor_mem
        ON sr.Sponsor = sor_mem.Id
    JOIN @membership AS sor_mship
        ON sor_mship.Member = sor_mem.Id
    JOIN @club AS c
        ON (see_mship.Club = c.Id
            AND sor_mship.Club = c.Id
            )
EXCEPT
SELECT
    see_mem.Name AS Sponsee
    ,sor_mem.Name AS Sponsor
    ,c.Name AS Club
FROM
    sponsored_relationships AS sr
    JOIN @member AS see_mem
        ON sr.Sponsee = see_mem.Id
    JOIN @membership AS see_mship
        ON see_mship.Member = see_mem.Id
    JOIN @member AS sor_mem
        ON sr.Sponsor = sor_mem.Id
    JOIN @membership AS sor_mship
        ON sor_mship.Member = sor_mem.Id
    JOIN @club AS c
        ON (see_mship.Club = c.Id
            AND sor_mship.Club = c.Id
            )
    JOIN @sponsorship AS sship
        ON (sship.Sponsee_Membership = see_mship.Id
            AND sship.Sponsor_Membership = sor_mship.Id
            );

问题在于您的数据模型。您是否能够更改它,或者您是否必须使用此模型编写SQL work around?听起来赞助不应该是会员之间的1对1关系,而是俱乐部会员与赞助商之间的关系。您的表
赞助
需要一个额外的列(它链接到的俱乐部)。作为进一步的示例,让我们以3名会员和3个俱乐部为例。珍妮、简和约翰,还有国际象棋、网球和读书俱乐部。约翰属于这三个人,但珍妮只属于书本和网球,简只属于象棋和书本。珍妮和简都是约翰的赞助商,这对国际象棋和网球俱乐部来说很有意义,但是读书俱乐部呢。你有“双重泡泡”吗?:)是的,问题的根源在于数据模型。不幸的是,这是无法修改的。这种次优的数据结构产生了一致的数据清理量。此问题与定期运行的许多必需的清理查询中的一个有关。@JClark Thx以获取澄清。很高兴你找到了答案。希望我整理您的问题/添加rextester和要点能让其他人更容易提供帮助!谢谢,这个很好用。你对数据模型的评论是完全准确的。很遗憾,我无权修改它。@JClark欢迎!如果你认为我的回答正确地回答了你的问题,请考虑…谢谢
Id   | Member          | Sponsor      | Club           | Dues
-----|-----------------|--------------|----------------|-----
6    | Rod Roosevelt   | John Jones   | Knitting Club  | 5
WITH sponsored_relationships AS (
    SELECT DISTINCT
        sponsee_member.Id AS Sponsee
        ,sponsor_member.Id AS Sponsor
    FROM
        @sponsorship AS s
        JOIN @membership AS sponsee_mship
            ON s.Sponsee_Membership = sponsee_mship.Id
        JOIN @member AS sponsee_member
            ON sponsee_mship.Member = sponsee_member.Id
        JOIN @membership AS sponsor_mship
            ON s.Sponsor_Membership = sponsor_mship.Id
        JOIN @member AS sponsor_member
            ON sponsor_mship.Member = sponsor_member.Id
    )
SELECT
    see_mem.Name AS Sponsee
    ,sor_mem.Name AS Sponsor
    ,c.Name AS Club
FROM
    sponsored_relationships AS sr
    JOIN @member AS see_mem
        ON sr.Sponsee = see_mem.Id
    JOIN @membership AS see_mship
        ON see_mship.Member = see_mem.Id
    JOIN @member AS sor_mem
        ON sr.Sponsor = sor_mem.Id
    JOIN @membership AS sor_mship
        ON sor_mship.Member = sor_mem.Id
    JOIN @club AS c
        ON (see_mship.Club = c.Id
            AND sor_mship.Club = c.Id
            )
EXCEPT
SELECT
    see_mem.Name AS Sponsee
    ,sor_mem.Name AS Sponsor
    ,c.Name AS Club
FROM
    sponsored_relationships AS sr
    JOIN @member AS see_mem
        ON sr.Sponsee = see_mem.Id
    JOIN @membership AS see_mship
        ON see_mship.Member = see_mem.Id
    JOIN @member AS sor_mem
        ON sr.Sponsor = sor_mem.Id
    JOIN @membership AS sor_mship
        ON sor_mship.Member = sor_mem.Id
    JOIN @club AS c
        ON (see_mship.Club = c.Id
            AND sor_mship.Club = c.Id
            )
    JOIN @sponsorship AS sship
        ON (sship.Sponsee_Membership = see_mship.Id
            AND sship.Sponsor_Membership = sor_mship.Id
            );