MySQL表关系 - 如果字段具有值

时间:2017-09-06 17:03:16

标签: mysql join

我的系统中可能有X个不同的表,还有一个表存储这些表的所有关系数据。例如,数据库看起来像这样

--------------------------        -----------------------------------
| Table fruits           |        |  Table drinks                   |
--------------------------        -----------------------------------
| id    | name           |        | id   | name                     |
--------------------------        -----------------------------------
| 1     | banana         |        | 1    | strawberry apple cocktail|
| 2     | apple          |        | 2    | banana juice             |
| 3     | strawberry     |        | 3    | cola                     |
--------------------------        -----------------------------------

--------------------------
| table food             |
--------------------------
| id    |  name          |
--------------------------
| 1     | apple  pie     |
--------------------------

关系表包含两个条目的id和表名。

--------------------------------------------------
| table relations                                |
--------------------------------------------------
| id  | table_1    | id_1   | table_2     | id_2 | 
--------------------------------------------------
| 1   | fruits     | 1      | drinks      | 2    | banana + banana juice
| 2   | fruits     | 2      | drinks      | 1    | apple + s.a. cocktail
| 3   | fruits     | 3      | drinks      | 1    | strawberry + s.a cocktail
| 4   | food       | 1      | fruits      | 2    | apple pie + apple
| 5   | drinks     | 3      | food        | 1    | if someone wants to mix it
--------------------------------------------------

如果我喝了一杯(草莓苹果鸡尾酒),我想得到属于它的所有水果ids(草莓和苹果),当我有水果(草莓)时,我想查询所有相关的喝ids。 所以我需要一个查询结构来查找双方,因为它是动态的,我不知道水果是在table_1还是table_2(否则它会很简单)

我希望有这样的东西(注意伪代码)来查询包含香蕉的饮料中的所有ID(表:fruits,id:1)

SELECT id
FROM drinks
LEFT JOIN relations AS rel ON drinks.id = (rel.table_1 == drinks)? rel.id_1 : rel.id_2
WHERE
((rel.id_1 = '1' AND rel.table_1 = 'fruits') OR ( rel.id_2 = '1' AND rel.table_2 = 'fruits' ))

我的问题

  1. 当我加入我的关系表只有一次时,我必须查询两次,因为我不知道我是否必须加入id_1或id_2
  2. 当我这样做2次加入时

    Select * from drinks LEFT JOIN relations AS relation1 ON drinks.id = relation1.id_1 LEFT JOIN relations AS relation2 ON drinks.id = relation2.id_2 WHERE ( (relation1.id_1 = '1' AND relation1.table_1 = 'fruits') OR ( relation2.id_2 = '1' AND relation2.table_2 = 'fruits' ) OR ( relation1.id_2 = '1' AND relation1.table_2 = 'fruits') OR ( relation2.id_1 = '1' AND relation2.table_1 = 'fruits'))
    我可以从两边搜索所有东西(有饮料 - >收到水果/有水果 - >收到饮料)但我也得到了与水果相同的饮料

    1. 我想避免select * from relations,因为我使用php构建查询,其他条件如fruit name,dateCreated等等,如果它包含关系,我将不得不重构整个查询

      您可以下载mysql dump here来测试它。我希望有人能帮助我。
  3. 谢谢你,我的英语不好

3 个答案:

答案 0 :(得分:0)

您的问题出在您的设计中,drink表与fruit表有多对多的关系,因此您应该将fruit_drink_relation表分开。

fruit_drink_food_relation的表存在相同的多对多关系。

要查找食物,查询第二个关系表,否则,第一个关系表就足够了。

答案 1 :(得分:0)

那里的设计非常糟糕。

请参阅,关系数据库管理系统拥有强大的机制,可以保持和实施实体之间的一致(!)关系(表示为表中的记录)。

为什么不按原样使用它?

从示例中可以看出,你有n..n(多对多)关系,而不是更多关系。

它有一个比它更常见的模式,关系表基本上由两列组成,这两列都是你需要连接在一起的实体的外键:

CREATE TABLE fruits_juices (
   fruit_id INT,
   juice_id INT
   FOREIGN KEY fruit_id
       REFERENCES fruits(id),
   FOREIGN KEY juice_id
       REFERENCES juices(id)
)

为你需要的每个关系做到这一点 - 就这样。

创建一些关系并没有什么不好 - 这是RDBMS应该工作的方式(因此他们最擅长的)。

不要尝试不必要的多才多艺:你的用例并不要求这样做。

在他们想要涵盖的所有情况下,太过一对一的解决方案通常并不好,并且需要额外的维护成本以防止它们崩溃(数据一致性,在您的情况下)

答案 2 :(得分:0)

我想你想要一个snowflake schema

看起来你现在正处于丑陋的一半。