【问题标题】:Joining tables and selecting foreign key where all rows meet condition in first table连接表并选择第一个表中所有行都满足条件的外键
【发布时间】:2015-02-20 20:57:47
【问题描述】:

我有两张桌子

帐户

ID  | Deleted? |  Type
1   |     0    |   Father
2   |     0    |   Son
3   |     1    |   Son
4   |     1    |   Son
5   |     0    |   Father
6   |     0    |   Father
7   |     1    |   Son
8   |     0    |   Son
9   |     0    |   Father
10  |     1    |   Son

Rel_Accounts

ID  | SON | FATHER 
 1  |  4  |   6
 2  |  3  |   6
 3  |  2  |   5
 4  |  4  |   1
 5  |  7  |   1
 6  |  8  |   9
 7  |  10 |   9

我只想选择活跃(已删除 =0)的父亲 ID,他们确实有 SON 已删除 = 1:

FATHERS
6
1

当 FATHER = 0 但他的所有 SONs Deleted = 1 时,您如何获得这些记录?

我尝试了以下方法,但没有成功:

SELECT A.ID,
    case when A.DELETED = 0
    THEN (SELECT AH.SONS FROM ACCOUNTS_REL AH WHERE AH.FATHER = A.ID AND A.DELETED = 1)
    END
FROM ACCOUNTS A 
WHERE A.TYPE = 'Father'

预期结果是 1 和 6,因为他们是活跃的父亲,并且 所有他们的儿子都被删除。

【问题讨论】:

  • 你尝试过什么吗?
  • 我在描述中添加了...

标签: mysql sql compare case


【解决方案1】:

如果你想要所有活跃的父亲,他的所有儿子都删除了这等于说所有活跃的父亲有儿子但没有活跃的儿子,那么试试下面:

select distinct rc.father
    from accounts a 
    join rel_accounts rc on a.id=rc.father
where a.deleted=0 
      and rc.father not in 
     (select qrc.father
             from accounts qa 
             join rel_accounts qrc on qa.id=qrc.father
      where qa.deleted=0 
            and qrc.son in 
           (select qracc.son
                   from rel_accounts qracc 
                   join accounts qacc on qracc.son=qacc.id
                   where qacc.deleted=0))
order by father desc

SQLFIDDLE DEMO

【讨论】:

  • 这很完美!你赚了一个加分,因为'同时这个用 NULL Sons 提取所有 FATHERS 记录,我没想到会这样。非常感谢。 :)
【解决方案2】:

在这种情况下,您需要使用多个连接来创建所需的数据集。如果我对您的理解正确,您希望过滤掉从结果集中删除的帐户记录,然后只返回代表有儿子的父亲的行。这样的事情就足够了:

Select distinct F.id from accounts F
join rel_accounts R on R.father=F.id
join accounts S on S.id=R.son
where F.deleted=0 and S.deleted=0;

联接本身会过滤掉您不想要的结果,然后您可以简单地从结果集中排除已删除的行。

其他人也许可以为你拼凑出一个稍微干净一点的版本。

【讨论】:

    【解决方案3】:

    正如我一直建议的那样,把它分解成几块,然后重新组合起来。

    首先获取活跃父亲的列表:

    SELECT id
    FROM accounts
    WHERE deleted = 0 AND type = 'Father';
    

    了解不活跃的儿子也很重要:

    SELECT id
    FROM accounts
    WHERE deleted = 1 AND type = 'Son'
    

    现在,只需从 rel_accounts 表中提取,其中父亲在第一个查询中,儿子在第二个查询中:

    SELECT *
    FROM rel_accounts
    WHERE father IN(
      SELECT id
      FROM accounts
      WHERE deleted = 0 AND type = 'Father')
     AND son IN(
       SELECT id
       FROM accounts
       WHERE deleted = 1 AND type = 'Son');
    

    编辑我认为这是解决方案,但经过测试,我意识到这并不能检查 每个 儿子是否已被删除。为此,我首先得到了每个父亲的儿子数量:

    SELECT father, COUNT(*) AS numSons
    FROM rel_accounts
    GROUP BY father;
    

    我使用相同的方法来获取每个活跃父亲的被删除儿子的数量:

    SELECT father, COUNT(*) AS numDeletedSons
    FROM rel_accounts
    WHERE father IN(
      SELECT id
      FROM accounts
      WHERE deleted = 0 AND type = 'Father')
     AND son IN(
       SELECT id
       FROM accounts
       WHERE deleted = 1 AND type = 'Son')
    GROUP BY father;
    

    然后我使用了一个连接到我的最后一个子查询。如果父亲删除的儿子数量与儿子总数相同,则应包括在内:

    SELECT a.father
    FROM(
      SELECT father, COUNT(*) AS numDeletedSons
      FROM rel_accounts
      WHERE father IN(
        SELECT id
        FROM accounts
        WHERE deleted = 0 AND type = 'Father')
      AND son IN(
        SELECT id
        FROM accounts
        WHERE deleted = 1 AND type = 'Son')
      GROUP BY father) a
    JOIN(
      SELECT father, COUNT(*) AS numSons
      FROM rel_accounts
      GROUP BY father) b ON b.father = a.father AND b.numSons = a.numDeletedSons;
    

    我在SQL Fiddle 中得到了您的预期结果。

    【讨论】:

    • 感谢您分段回答,我学到了很多。你的精彩程度正在突破极限。 :) 我不知道我的 Rel_Accounts 表有 NULL 值(没有儿子的父亲活动)@Farhang Amary 'Ferhęg 的查询解决了这个问题。您的查询从原始问题中提取所有记录。非常感谢! :)
    • @axor 很高兴我能帮上忙。你从来没有在你的问题中提到过空子,所以我认为这不是一个考虑因素。
    猜你喜欢
    • 1970-01-01
    • 2019-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    相关资源
    最近更新 更多