跨多个表的复杂查询

时间:2011-10-03 11:46:25

标签: mysql

我正在简化我的实际案例,以便更快地获得重点,如果这似乎是荒谬的话,就像抬头一样。

我有一张叫做Candy_Central的桌子。 Candy_Central拥有我糖果的所有ID,每磅的价格以及所有Candy记录中相同的其他重要信息。它还有一个名为Candy_Type的字段。 Candy_Type的值可能是巧克力,坚硬,粘性或液体。

我有另一组用于糖果信息的表,但它们的用途由糖果类型决定。例如,如果我想要关于我的主要巧克力棒的其他信息,我需要去Chocolate_Standard获取其余的信息。如果我在外面查找带糖的​​粘性蠕虫,我需要去Gummy_Standard。原因是一组信息的字段与另一组信息的字段完全不同。

我还有一层信息,颜色。我的糖果是蓝色的,我的糖果是黑色的,我的糖果都是两种颜色。我目前正在存储此信息的方式,我有一个包含字段Candy_IdColor的表格。为了找到所有的颜色,我通常只使用color_id字段对此表进行查询,以找到我感兴趣的糖果。但SQL当然是关于查找所有结果。因此,如果我想找到所有的粘性信息,我想要进行某种联接或联合。我不是非常熟悉这种类型的查询,所以我不知道如何获得我想要的结果表,这基本上是[抱歉的伪造查询](来自Candy_Main的项目为CM ...项目从Gummy作为g ...颜色的项目为c ...其中cm.candy_id = g.candy_id和cm.candy_id = c.candy_id)。如果胶粘剂没有颜色,我只想要null。我很好地为每个candy_id获取了多行,但是我希望它尽可能地限制,以便后期处理(将多个糖果线转换为我的应用程序中的一个对象)花费的时间尽可能少。

表:

Candy_Main
    candy_id (primary key, auto increment, not null, etc)
    candy_name (varchar)
    candy_inventor_id (a primary key from some other table, but this is needed for the where clause.
    candy_type (varchar)

Gummy_Standard
    gummy_id (primary, auto)
    candy_id (should match to candy_main)
    softness (varchar)
    outer_coating_type (varchar)
    animal_likeness (varchar)

Gummy_Colors
    gummy_color_id (primary, auto)
    gummy_id (int)
    candy_id (int)
    color (varchar(64))

Gummy_Ingredients
    gummy_ingredient_id (primary, auto)
    gummy_id (int)
    candy_id (int)
    ingredient (varchar(64))

现在,我想对所有条目where candy_inventor_id = 5 AND candy_type = 'gummy'进行查询。在查询结束时,我想要candy_name, candy_type, softness, outer_coating_type, animal_likeness, colors, and ingredients

颜色&在这个查询中,成分是唯一不是1比1的对象,所以我希望其中只有颜色和成分的条目数量。如果可能的话,感谢您的帮助。我有一种感觉,仅仅为了颜色或只是成分来限制它是很容易的,但是用这两种方法来做它会很困难。

2 个答案:

答案 0 :(得分:1)

试试这个

SELECT c.candy_name, c.candy_type, s.softness, s.outer_coating_type, 
      s.animal_likeness, 
      GROUP_CONCAT(gc.color), 
      GROUP_CONCAT(gi.ingredient)
FROM candy_main c
LEFT JOIN gummy_standard s on s.candy_id=c.candy_id
LEFT JOIN gummy_colors gc on gc.candy_id = c.candy_id
LEFT JOIN gummy_ingredients gi cl on cl.candy_id = c.candy_id
WHERE c.candy_inventor_id=5 AND c.candy_type='gummy'
GROUP BY gc.color , gi.ingredient

答案 1 :(得分:1)

如果我理解你的数据库设置正确,对于每个糖果,有许多潜在的gummy_standards(因此硬熊和巧克力熊可能是两个与一个糖果记录相关的粘性标准记录)。在这种情况下,以下应该有效:

SELECT cm.candy_name, cm.candy_type, gs.softness, gs.outer_coating_type, gs.animal_likeness, gc.color, gi.ingredient
FROM Candy_Main cm
    INNER JOIN Gummy_Standard gs ON gs.candy_id = cm.candy_id
    INNER JOIN Gummy_Colors gc ON gc.candy_id = gs.gummy_id
    INNER JOIN Gummy_Ingredients gi ON gi.gummy_id = gs.gummy_id
WHERE candy_inventor_id = 1  -- Of course, this 1 be replaced with the actual inventor's ID

请记住,这样做会导致重复交叉繁殖,所以如果一个胶粘有三种颜色和4种成分,则每种成分都会重复所有三种颜色(因此只有一种胶粘就会重复12行)。如果您不想这样做,请尝试将字符串连接到一行,然后在代码中拆分该行。不知道MySQL中的函数是什么,但是如果concat_ws()的工作方式与PostgreSQL中的textcat_all()相同,那么以下内容应该可以工作:

SELECT cm.candy_name, cm.candy_type, gs.softness, gs.outer_coating_type, gs.animal_likeness, CONCAT_WS(', ', gc.color), CONCAT_WS(', ', gi.ingredient)
FROM Candy_Main cm
    INNER JOIN Gummy_Standard gs ON gs.candy_id = cm.candy_id
    INNER JOIN Gummy_Colors gc ON gc.candy_id = gs.gummy_id
    INNER JOIN Gummy_Ingredients gi ON gi.gummy_id = gs.gummy_id
WHERE candy_inventor_id = 1  -- Of course, this 1 be replaced with the actual inventor's ID
GROUP BY cm.candy_name, cm.candy_type, gs.softness, gs.outer_coating_type, gs.animal_likeness

关于架构的两个提示:
1.如果我对你的桌子的理解是正确的,并且成分和颜色总是适用于粘性标准记录,那么颜色和成分中的candy_id字段是多余的。最好只通过Gummy Standard连接到Candy。每次 2.您可能会受益于更高程度的规范化,即创建颜色表和成分表,然后链接到那些,而不是在表中包含字符串描述。这样可以更容易地对所有适当的记录进行更改,也就是说您想要将蓝色的名称更改为蓝色(深色),因为您要添加蓝色(浅色),您只需要更新一个记录而不是所有颜色记录都说蓝色(或蓝色,甚至蓝色或blou,因为每次必须输入相同的描述时经常会出现拼写错误)。所以你的表看起来像:

Color
    color_id (primary, auto)
    color (varchar(64))

Ingredient
    ingredient_id (primary, auto)
    ingredient (varchar(64))

Gummy_Colors  
    gummy_color_id (primary, auto)  
    gummy_id (int)  
    candy_id (int)  
    color_id (foreign key to Color)  

Gummy_Ingredients  
    gummy_ingredient_id (primary, auto)  
    gummy_id (int)  
    candy_id (int)  
    ingredient_id (foreign key to Ingredient)  

希望这有帮助。