连接表并选择所有行满足第一个表中条件的外键

时间:2015-02-20 20:57:47

标签: mysql sql compare case

我有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

我想只选择有SONs Deleted = 1的有效(已删除= 0)父亲ID:

FATHERS
6
1

当FATHER = 0但所有SONs删除= 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,因为他们是活跃的父亲,他们儿子的所有都被删除。

3 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

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

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;

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

其他人可能会为您准备一个稍微清洁的版本。

答案 2 :(得分:0)

正如我一直建议的那样,把它分解成几块并将它们放回原处。

首先获取活跃父亲的名单:

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

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

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

现在,只需从第一个查询中父亲为IN的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得到了您的预期结果。