加入 tables 并选择外键,其中所有行都满足第一个 table 的条件

Joining tables and selecting foreign key where all rows meet condition in first table

我有2张桌子

帐户

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

我想 select 仅 select 已删除 SON 的活跃(已删除 =0)父亲 ID = 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,因为他们是活跃的父亲,他们的所有 个儿子都被删除了。

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

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

在这种情况下,您需要使用多个联接来创建所需的数据集。如果我对你的理解是正确的,你想过滤掉从结果集中删除的帐户记录,那么 return 只有代表有儿子的父亲的行。这样的东西就足够了:

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;

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

其他人也许可以为您拼凑出一个更简洁的版本。

就像我一直建议的那样,把它拆成碎片,然后把它们重新组合起来。

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

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

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

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

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

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');

EDIT 我认为这是解决方案,但在测试后我意识到这并没有检查 every 儿子是否已被删除。为此,我首先得到每个父亲的儿子数量:

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 中得到了你预期的结果。