【问题标题】:How to select unique rows from one to many relationed tables in MySQL?如何从 MySQL 中的一对多关系表中选择唯一行?
【发布时间】:2011-08-03 06:51:46
【问题描述】:

作为 MySQL-Noob,我正在努力解决以下任务:假设 3 个表:locationgroceriesperson,具有以下属性:

  1. 每个表都有一个主要的自动递增整数 id 和一个 varchar 列。
  2. 表中的条目都是唯一的。
  3. groceries 中的每个条目都有一个 person 中条目的外键。
  4. groceries 中的多个条目可能共享同一个外键。
  5. (3) 和 (4) 也适用于 personlocation

所以我们有一个多对一对多的关系。如何选择每个三重 (groceries_product, person_name, location_name),其中 person_name 不出现多次?

例子:

tables:  groceries                  | person      | location
------------------------------------ ------------- -------------------------
columns: id  product      person_id | id  name    | id  name  person_id
------------------------------------ ------------- -------------------------
         1   hamburger    1         | 1   Peter   | 1   home  1
         2   cheeseburger 1         | 2   Tom     | 2   work  1
         3   carot        1         |             | 3   zoo   2 
         4   potatoe      1         |             |
         5   mango        2         |             |

您可以创建的所有出现Peter 的三元组都无关紧要。我只想要像 (mango, Tom, zoo) 这样的三元组,因为 Tom 在所有可能性中只出现一次。我希望我的问题是可以理解的。 :-)

【问题讨论】:

  • 如果你给这些表名和列名就好了。 10 次中有 9 次,在提出问题时将真正的问题简化为微不足道的假问题,但你并没有得到真正问题的正确答案。
  • @Dan Grossman:我试图改进这个问题。这样更好吗?
  • @丹·格罗斯曼。我做到了。我认为您建议更改问题以提高可读性。

标签: mysql select unique


【解决方案1】:

我认为您必须进行子选择才能获得结果:

SELECT groceries.product, person.name, location.name
FROM person
LEFT JOIN groceries ON person.id = groceries.person_id
LEFT JOIN location ON person.id = location.person_id
WHERE person.id
IN (
SELECT person.id
FROM person
LEFT JOIN groceries ON person.id = groceries.person_id
LEFT JOIN location ON person.id = location.person_id
GROUP BY person.id
HAVING count( person.id ) =1
)

【讨论】:

  • 请问:首先,您加入(笛卡尔积)表并仅生成人员条目仅出现一次的行。这意味着如果一个人的名字出现在笛卡尔积的两行中,你就把它们都扔掉。然后您再次加入并仅选择行,其人员条目在第一组中可用。我是否理解您的问题?
  • 是的,你明白了。内部选择给出了在所有三个表的笛卡尔积中只出现一次的 person_ids。我总是使用左连接来进行此类连接。我不知道为什么——我认为这是我的一个(坏)习惯。然后在外部选择中,我选择输出所需的表和列,并通过内部选择的 person_ids 进行过滤。
  • 它似乎工作,虽然它需要一些时间。 :-) 非常感谢您的努力!
  • 那么最好将我的答案标记为正确答案。 :) 要优化您的数据库/选择,只需在您的选择语句前面放一个 EXPLAIN 并分析结果。如果有任何连接在“type”列中显示“ALL”,那么通过插入索引可以获得很多性能。对于您的表结构,为所有外键列添加索引(如果尚未完成)是有意义的,您会看到,选择将运行得非常快。
【解决方案2】:
select l.name, m.name, r.name
from `left` l
left join middle m on m.id = l.middle_id
left join `right` r on m.id = r.middle_id;

【讨论】:

  • 这不满足要求(“其中middle_entry 不会出现多次”),甚至不能正确地将表连接在一起。
  • on r.id = r.middle_id... 不,它没有,你永远不会加入中间和右边的桌子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-15
  • 2023-03-10
  • 1970-01-01
  • 2017-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多