加入belongs_to表并返回只有很多行作为其中一行的最大行?

时间:2017-08-11 16:23:45

标签: mysql database

我看了lot个试图解决这个问题的问题,最后得到了一个符合我想要的问题。但我想知道是否有更好的方法来做到这一点?基本上,由于belongs_to关系,我有一堆表连接在一起,我希望返回的行数只能与其中一个belongs_to表中的最大行数一样多。

由于这是一种笨拙的措辞,这是一个例子。说我有2个食谱,每个都有步骤和一些营养。配方1有3个步骤和3个营养,配方2有2个步骤和4个营养。对于配方1,最多应返回3行,对于配方2,最多应返回4行。这是数据的小提琴:http://sqlfiddle.com/#!9/bcce59/2

如果小提琴由于某种原因不起作用,这里是表格模式:

CREATE TABLE recipe
    (`id` int PRIMARY KEY, `title` varchar(64))
;

CREATE TABLE step
    (`rid` int, `instruction` varchar(64),
    FOREIGN KEY(rid) REFERENCES recipe(id) )
;

CREATE TABLE nutrition
    (`rid` int, `name` varchar(64), `amount` int,
    FOREIGN KEY(rid) REFERENCES recipe(id) )
;

以下是一些示例数据:

INSERT INTO recipe
    (`id`, `title`)
VALUES
    (1, 'Cookies'),
    (2, 'Bananas')
;

INSERt INTO step
    (`rid`, `instruction`)
VALUES
    (1, 'Unwrap'),
    (1, 'Dip in milk'),
    (1, 'Eat'),
    (2, 'Peal'),
    (2, 'Eat')
;

INSERT INTO nutrition
    (`rid`, `name`, `amount`)
VALUES
    (1, 'calories', 120),
    (1, 'sugar', 300),
    (1, 'fat', 50),
    (2, 'calories', 50),
    (2, 'sugar', 50),
    (2, 'fat', 20),
    (2, 'carb', 30)
;

现在,我想我最初可能会和小组一起做这件事。但是像

这样的东西
SELECT id, title, instruction, name, amount FROM
recipe 
LEFT JOIN step ON recipe.id = step.rid
LEFT JOIN nutrition on recipe.id = nutrition.rid
GROUP BY id, instruction, name, amount;

将返回17行,因为它是一个产品,并且按列分组的唯一配对数对于配方1为9,对于配方2为8.这样就可以了。在标签之间进行了大量搜索并倾注了MySQL文档和我所拥有的食谱书之后,我想出了以下查询来完成这项工作:

SELECT id, title, instruction, name, amount FROM 
(
    SELECT 
        id, 
        title, 
        instruction, 
        name, 
        amount
    FROM recipe 
        LEFT JOIN step ON recipe.id = step.rid
        LEFT JOIN nutrition on recipe.id = nutrition.rid
) data
INNER JOIN 
(
    SELECT 
        s.rid,
        CASE
            WHEN
                GREATEST(numSteps, numNutrition) = numSteps
            THEN instruction
            WHEN
                GREATEST(numSteps, numNutrition) = numNutrition
            THEN name
        END as row
    FROM 
    (
        SELECT
            rid,
            instruction
        FROM step GROUP BY rid, instruction 
    ) s
    LEFT JOIN
        (
            SELECT
                rid,
                name
            FROM nutrition GROUP BY rid, name
        ) n
    ON s.rid = n.rid
    LEFT JOIN
        (
            SELECT rid, COUNT(*) as numNutrition 
            FROM nutrition GROUP BY rid
        ) nSum
    ON n.rid = nSum.rid
    LEFT JOIN
        (
            SELECT rid, COUNT(*) as numSteps 
            FROM step GROUP BY rid
        ) sSum
    ON s.rid = sSum.rid
    GROUP by rid, row
) biggest 
ON data.id = biggest.rid 
GROUP BY data.id, biggest.row
;

然而,将我的宝贝2个belongs_to表的例子推广到我的实际数据库,其中有超过20个表加入,这让我很担心。当使用天真的连接方法时,我的真实数据每个'recipe'有15k到90k行,所以我关心查询的性能以及我可能只是缺少一些非常基本和简单的东西来帮助解决这个问题。我真的不想写一个存储过程来做这个,虽然我想知道一个视图表是否有意义?我的问题是

  • 有没有办法以更好/更高效的方式编写上述查询?
  • 构建一个视图表或类似的东西来有效地缓存可能冗长而痛苦的查询的结果是否有意义?

为奇怪的问题标题道歉,我不知道如何简洁地说出我正在对此查询做什么。

我意识到我的小提琴没有产生正确的数据,所以这里是一个编辑,以明确查询的最终结果集应该是什么:

+----+---------+-------------+----------+--------+
| id | title   | instruction | name     | amount |
+----+---------+-------------+----------+--------+
|  1 | Cookies | Unwrap      | calories |    120 |
|  1 | Cookies | Dip in milk | sugar    |    300 |
|  1 | Cookies | Eat         | fat      |     50 |
|  2 | Bananas | Peel        | calories |     50 |
|  2 | Bananas | Peel        | sugar    |     50 |
|  2 | Bananas | Eat         | fat      |     20 |
|  2 | Bananas | Eat         | carb     |     30 |
+----+---------+-------------+----------+--------+
7 rows in set (0.00 sec)

这样的事情,每个指令/营养价值在结果集中至少出现一次。对于那些与其他belongs_to表相比没有最大行数的列,允许重复。

0 个答案:

没有答案