【问题标题】:How do I structure a SQL query to find an object that is the parent of two specific other objects?如何构建 SQL 查询以查找作为两个特定其他对象的父对象的对象?
【发布时间】:2014-06-01 08:00:50
【问题描述】:

假设我有 2 个表,分别称为 parent 和 child。一个父母可以有零到多个孩子,一个孩子可以有 1 到多个父母。如何找到作为两个特定子级的父级的所有父级元素。

例如,假设我有父母 [p_a, p_b, p_c, p_d] 和孩子:[c_a, c_b] 它们的结构如下:

  • p_a 有 c_a 作为孩子
  • p_b 有 c_b 作为孩子
  • p_c 有 c_a 和 c_b 作为孩子
  • p_d 没有孩子

如何制定查询以选择 p_c?

如果他们有一个结构,其中 p 有 [id, name] 并且 c 有 [id, name] 并且有一个带有 [parent_id, child_id] 的 join_table。 (我还为这个示例提供了顺序 ID,以使事情变得更容易)。

我尝试解决这个问题时提出了以下 SQL

SELECT p.*
FROM parent AS p
JOIN join_table AS j ON p.id = j.parent_id
JOIN children AS c ON j.child_id = c.id
WHERE c = 1
  OR c = 2

但显然这会选择 p_a 和 p_b 以及 p_c。我一直在查看 UNION 运算符,但似乎无法正常工作。

期待您的回答,感谢阅读。 迈克

编辑:提到了我在示例中使用的 id 约定

【问题讨论】:

  • 在你的例子中 c_a 有 id=1,c_b id=2 ?
  • @GrzegorzMotyl 抱歉,这是我使用的约定,只是意识到我没有指定它们。

标签: mysql sql database relational-database


【解决方案1】:

您正在寻找存在两个特定子记录的父母。为此使用 EXISTS 子句:

SELECT *
FROM parent p
WHERE EXISTS (select * from join_table j where j.parent_id = p.id and j.child_id = 1)
  AND EXISTS (select * from join_table j where j.parent_id = p.id and j.child_id = 2);

【讨论】:

  • 正是我想要的那种东西,谢谢 Thorsten。
  • 快速问题,是否可以将连接保留在外部主体中(如在父 p 之后)。键入此内容时,我想我意识到您不能这样做,因为那样它仍然会遇到与原始查询相同的问题。无论如何都会发布以确认我理解正确(并且连接必须是存在的“孩子”)
  • 当您想向孩子们展示他们的父母时,您可以加入父表。然后你必须考虑,你真正想在你的结果列表中看到什么。一条记录是 p_c 和 ca,另一条记录是 pc 和 c_b?或者只有一条记录 p_c 和一些关于孩子的聚合(比如平均年龄或包含他们名字或其他东西的字符串)。当您想通过 children 表中的某些条件查找子项时,您可以加入 exists 子句。
  • 谢谢,您不能将我指向一个资源,在那里我可以阅读有关如何创建包含两个名称的字符串的信息,您可以吗? (文档链接很好,我只是不知道有什么功能可以做到这一点!我觉得我应该了解它。)
  • MySQL 有 GROUP_CONCAT 。使用 niklon 的查询以及与子表的连接。这是 MySQL 聚合函数的链接:dev.mysql.com/doc/refman/5.0/en/group-by-functions.html
【解决方案2】:

接受答案的替代方案,可能更快:

SELECT p.*
FROM parent p JOIN join_table j ON p.id=j.parent_id
WHERE j.child_id=1 OR j.child_id=2
GROUP BY j.parent_id
HAVING COUNT(j.child_id)=2;

【讨论】:

  • 感谢您的回答,您已经解决了这个特定示例,不幸的是,我正在寻找一种更通用的方法来使用可变数量的参数。我的错,我应该更清楚。谢谢你的努力。 (显然 +1 用于优化我给出的案例)
  • 我认为这比公认的答案更笼统。不在代码中 - 您仍然需要以类似的方式更改两个查询 - 但在效率方面。无论您想要多少个子节点作为参数,此查询将始终产生一个连接和一个线性时间过滤 where 条件。对于接受的答案,同样不能说(如果没有对 DB 的优化算法有更深入的了解),其中一个额外的孩子可能会增加一个复杂度顺序(n^2、n^3、n^4 等等)。
  • 当然好点,但是当有孩子 c_a、c_b 和 c_c 并且我们只想要 c_a 和 c_b(完全正确)时,我认为这行不通,就像有 c_a 和 c_c 一样,那仍然会通过查询(如果我错了,请纠正我)。 (我没有具体说明该要求是我所说的我犯了一个错误,因为不够清楚)。
  • 不,因为 where 子句,带有 c_c 的行不会被包括在内。
  • 啊……我认为你是对的。不确定我是否完全理解...谢谢,我觉得这真的会加快速度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-18
相关资源
最近更新 更多