【问题标题】:Complex query across multiple tables跨多个表的复杂查询
【发布时间】:2011-11-29 21:02:11
【问题描述】:

我正在简化我的实际案例,以便更快地理解这一点,如果这看起来很荒谬,请提醒一下。

我有一张名为 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 )。如果软糖没有颜色,我只想为空。我可以为每个 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 的对象,因此我希望条目的数量与颜色和成分的数量一样多。如果可能的话,感谢您的帮助。我有一种感觉,将其限制为仅用于颜色或仅用于成分很容易,但同时使用这两种方法就太难了。

【问题讨论】:

    标签: mysql


    【解决方案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. 您可能会受益于更高程度的规范化,即创建一个颜色表和一个成分表,然后链接到它们,而不是按原样在表中包含字符串描述。这将更容易对所有适当的记录进行更改,即假设您想将蓝色的名称更改为蓝色(深),因为您要添加蓝色(浅),您应该只需要更新一条记录而不是所有的颜色记录都说蓝色(或蓝色,甚至是蓝色或蓝色,因为当您每次都必须输入相同的描述时,经常会出现拼写错误)。所以你的表格看起来像:

    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)  
    

    希望这会有所帮助。

    【讨论】:

    • 确实如此,我想我现在想查找外键。 :)。不幸的是,我没有很好地输入介绍。 cm & gs 应该是 1 比 1。成分表和颜色表是单个 candy_id 的唯一一对多关系。不过谢谢。尽管如此,你还是让我有一些事情要考虑。
    【解决方案2】:

    试试这个

    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
    

    【讨论】:

    • 我最后只有一排所有信息都被展平了。也就是说,GROUP_CONCAT 看起来是一个有前途的进一步研究方向。会不会是没有 GROUP_BY?
    • 想通了。我输入了 ORDER BY。我的错。谢谢,这会做。我在 GROUP CONCAT 列表中得到了一些复制,可能是因为使用了多个表,我想将其清除,但这可以等待。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2013-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    相关资源
    最近更新 更多