【问题标题】:selecting the ID that fulfils multiple clauses选择满足多个子句的 ID
【发布时间】:2012-02-07 09:26:30
【问题描述】:

很难正确输入,但是我使用的是MySQL,我需要选择一个id,我们称之为parent_id,它必须满足多行的child_id值。

例如:

   +-----------+----------+
   | parent_id | child_id |
   +-----------+----------+
   |     1     |    10    |
   +-----------+----------+
   |     2     |    11    |
   +-----------+----------+
   |     2     |    12    |
   +-----------+----------+
   |     3     |    13    |
   +-----------+----------+
   |     4     |    11    |
   +-----------+----------+
   |     5     |    12    |
   +-----------+----------+

现在,如果我传递 child_id 参数 11 和 12,我必须取回 parent_id 2,但如果我传递 10 和 11,我将什么也得不到。另外,如果我通过 11,我必须收到 4。如果我通过 13,我必须收到 3。

我该怎么做?我尝试计算 parent_id 并使用 HAVING 子句,也使用 GROUP BY 子句,但我尝试的都没有满足我的所有要求。

编辑:

小提琴示例:http://sqlfiddle.com/#!2/abbc4/5

EDIT2:

预期结果:

传递的参数:11、12 收到的结果:2

传递的参数:11 收到的结果:4

传递的参数:13 收到的结果:3

传递的参数:12、13 收到结果为NULL

EDIT3:

更新了规范。参见这里:http://sqlfiddle.com/#!2/2f750/1

【问题讨论】:

  • 哇!甚至谷歌翻译也无法帮助我理解这一点。
  • 这不是 OP 的错。这很容易理解:他想创建一个查询,仅当所有对应的child_ids 都已指定且未指定属于不同parent_idchild_id 时才返回parent_id
  • 10, 13 会得到什么。没有?还是13?或者:对于11, 12, 13:什么都没有?还是23
  • @donkapone 现在,根据您的最新更新,child_id in (11,12) 应该返回 null。请同时更新您的描述现在如果我传递 child_id 参数 11 和 12,我必须获取 parent_id 2 并更新 传递的参数:11、12 收到的结果:2跨度>
  • 但是如果我传递 child_ids 11 和 12,它仍然应该返回 parent_id 2,但是如果我只传递 11 作为 child_id,它应该返回 parent_id 4,而不是 parent_id 2,因为 parent_id 2 有更多 child_ids而不仅仅是 11。换句话说,要获得所需的 parent_id,您必须传递其所有子代。不多不少。

标签: mysql sql select


【解决方案1】:

以下语句可以满足您的要求。不过我不太确定它的性能...

select t.parent_id, t.cnt from
(
    select parent_id, count(*) cnt
    from t 
    WHERE child_id IN (12, 11)
    GROUP BY parent_id
) t
inner join
(
    select parent_id, count(*) cnt
    from t group by parent_id
) s
on t.parent_id = s.parent_id
and t.cnt = s.cnt -- Check that the parent has exactly as many children as
                  -- passed in - and not more. Prevents matching if only part
                  -- of the children of a parent were specified.
and t.cnt = 2 -- Check that all passed in children produced a match on the same
              -- parent. Prevents matching of parents that match only a subset
              -- of the specified children

2 替换为IN 列表中指定子代的数量。

【讨论】:

  • 你在这里创造了奇迹。不幸的是,我没有写出完全正确的规范。我将用完整的欢呼来更新问题。
  • 我仍然在 PHP 中解决了一些问题,并进行了更多查询,因为正如预期的那样,该查询没有为脚本提供足够的性能。不过,很高兴知道也可以这样做。
  • @donkapone:确保你有正确的索引。这应该会显着加快查询速度。
  • 他们都在那里。不过,它仍然非常快 - 查看 20MB 具有 100k 行的大表需要 50 毫秒。
【解决方案2】:

你也可以使用这个更紧凑的版本

select case
         when min(t.parent_id) = max(t.parent_id) -- parent_ids are the same?
              -- and all children share the same parent?
              and count(t.parent_id) = (
                          select count(parents.parent_id)
                            from t parents
                           where parents.parent_id in
                              (select parent_id
                                 from t 
                                where child_id in (11, 12) -- <= change here
                               )) 
         then t.parent_id
         else null
       end as parent_id
  from t 
 where child_id in (11, 12); -- <= and here

我已经对此进行了测试,适用于您的所有用例

你可以在这里测试http://sqlfiddle.com/#!2/abbc4/183

【讨论】:

    【解决方案3】:

    你必须有两个变量才能工作。第一个是您的 child_id 的逗号分隔列表 (child_list),第二个是您正在搜索的孩子的数量(您的 child_list 中的孩子数) (child_count)。

    SELECT parent_id,COUNT(*) 
    FROM table 
    WHERE child_id IN (<child_list>) 
    GROUP BY parent_id
    HAVING COUNT(*)=<child_count>
    

    这应该会给你想要的结果。

    【讨论】:

    • 我喜欢你优雅的回答。但是,这难道不是只有在您已经知道要查找的父对象并因此知道其子对象的数量时才有效吗?
    • @DanielHilgarth 如果我正确理解了 OP,他的问题是“我有孩子 x,y,z 并且想知道他们是否都与共同的父母有关”。然后你就会知道孩子的数量。
    • OP 在他的回答中明确指出他希望匹配的父级作为返回值。所以父母是预期的结果,而不是输入的一部分。
    • @DanielHilgarth 正确。如果所有 child_id 都与一个共同的父级相关,我的语句将返回 parent_id。 parent_id 是结果,而不是输入。
    • child_count 来自哪里?如果是count(child_list),您的查询会产生错误的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多