Mysql 联接属于表,并且返回的表中只有多行作为最大行?
我看了很多问题,试图弄明白这一点,最后得到了一个符合我要求的查询。但我想知道有没有更好的方法?本质上,我有一堆表,它们由于属于关系而连接在一起,我希望返回的行数与其中一个属于表中的最大行数相同 因为这是一种笨拙的措辞,这里有一个例子。假设我有两个食谱,每个都有步骤和一些营养。配方1有3个步骤和3种营养,配方2有2个步骤和4种营养。对于配方1,最多应返回3行,对于配方2,最多应返回4行。这里是一个数据的摆弄: 如果由于某种原因小提琴不起作用,以下是表格模式:Mysql 联接属于表,并且返回的表中只有多行作为最大行?,mysql,database,Mysql,Database,我看了很多问题,试图弄明白这一点,最后得到了一个符合我要求的查询。但我想知道有没有更好的方法?本质上,我有一堆表,它们由于属于关系而连接在一起,我希望返回的行数与其中一个属于表中的最大行数相同 因为这是一种笨拙的措辞,这里有一个例子。假设我有两个食谱,每个都有步骤和一些营养。配方1有3个步骤和3种营养,配方2有2个步骤和4种营养。对于配方1,最多应返回3行,对于配方2,最多应返回4行。这里是一个数据的摆弄: 如果由于某种原因小提琴不起作用,以下是表格模式: CREATE TABLE recipe
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行,因为它是一个产品,并且group by列的唯一对数对于配方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推广到实际数据库的表中,该数据库有20多个表要连接,这让我很担心。当使用NaiveJoin方法时,我的实际数据每个“配方”有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)
类似这样,每个指令/营养值在结果集中至少出现一次。与其他属于表的列相比,行数不多的列允许重复。使用MySQL获取数据。使用其他语言来格式化它。这是我喜欢的烹饪方式。和我的水平差不多。但我会“剥”香蕉皮。@Spiegel不幸的是,试图在应用层处理这么多行会导致问题,这就是为什么我们要到MySQL层看看是否可以在那里修复它。对于20个项目,我们得到了400k+行,如果我们让mySQL缓冲,这会导致OOM错误,但是如果我们切换到fetch size=min的流,那么将数据发送回应用程序和连接会花费太长时间。似乎您在应用层中做了一些错误的事情。但这并不是在SQL中这样做(错误)的理由。您对样本数据的预期结果是什么?您的应用程序语言是什么?注意:这并不是因为连接不好。这是因为这样的连接没有逻辑意义。使用配方上的
LEFT JOIN step.id=step.rid配方上的LEFT JOIN nutrition.id=nutrition.rid
可以在组内创建交叉联接。您可以像这样使用子查询和group\u concat
。但您会得到一个comlex代码,并将输出格式放在SQL中。我会尽量避免两者。使用MySQL获取数据。使用其他语言来格式化它。这是我喜欢的烹饪方式。和我的水平差不多。但我会“剥”香蕉皮。@Spiegel不幸的是,试图在应用层处理这么多行会导致问题,这就是为什么我们要到MySQL层看看是否可以在那里修复它。对于20个项目,我们得到了400k+行,如果我们让mySQL缓冲,这会导致OOM错误,但是如果我们切换到fetch size=min的流,那么将数据发送回应用程序和连接会花费太长时间。似乎您在应用层中做了一些错误的事情。但这并不是在SQL中这样做(错误)的理由。您对样本数据的预期结果是什么?您的应用程序语言是什么?注意:这并不是因为连接不好。这是因为这样的连接没有逻辑意义。使用配方上的LEFT JOIN step.id=step.rid配方上的LEFT JOIN nutrition.id=nutrition.rid
可以在组内创建交叉联接。您可以像这样使用子查询和group\u concat
。但您会得到一个comlex代码,并将输出格式放在SQL中。我会尽量避免两者。