我想知道是否有更好的方法来编写此查询(相同table的多个连接)
I would like to know if there is a better way to write this query (multiple joins of the same table)
问题是:
我在db中有车辆table(这个table的字段不是那么重要),重要的是每辆车都有一个model_id,它指的是vehicle_models table.
车辆型号 table 有 id、class、型号、系列、cm3hp、created_at 和 updated_at 字段。
我需要根据给定标准根据库存中特定型号 class 的车辆数量来定义库存年龄。标准是:0-30 天、31-60 天、61-90 天……360 天以上……
我不知道它是否足够清楚,但让我试着解释得更好:对于每天的范围,我需要找到给定型号 class 的车辆数量。还有其他标准,但这对我要找出的内容并不重要。为了帮助您更好地理解问题,我将包括结构应该是什么样子的屏幕截图:
我正在使用 MySQL 8.
我写的查询是:
SELECT DISTINCT vm.class,
IFNULL(t1.count, 0) as t1c,
IFNULL(t2.count, 0) as t2c,
IFNULL(t3.count, 0) as t3c,
IFNULL(t4.count, 0) as t4c,
IFNULL(t5.count, 0) as t5c,
IFNULL(t6.count, 0) as t6c,
IFNULL(t7.count, 0) as t7c
FROM vehicle_models vm
LEFT JOIN (
SELECT
vm.class as class,
count(*) as count
FROM a3s186jg7ffmm0q8.vehicles v
JOIN vehicle_models vm
ON vm.id = v.model_id
WHERE
DATEDIFF(IFNULL(v.retail_date, now()), v.wholesale_date) BETWEEN 0 AND 30
GROUP BY vm.class
) t1 ON t1.class = vm.class
*** MORE SAME LEFT JOINS ***
ORDER BY vm.class;
现在,这提供了所需的结果,但我想知道是否有更好的方法来编写此查询,以提高性能和代码结构。
我猜您是在提交一份库存老化报告(这辆车在有人购买之前在经销商处停放了多长时间)。您可以将年龄范围放在顶级 select 中,而不是将每个年龄范围放在单独的子查询中。这将使您的查询更快(子查询有成本)并且更短/更易于阅读。
尝试像这样的嵌套查询。内部查询返回每辆车一行及其老化编号。外部查询聚合它们。
SELECT class,
COUNT(*) total,
SUM(age BETWEEN 0 AND 30) t1c,
SUM(age BETWEEN 31 AND 60) t2c,
SUM(age BETWEEN 61 AND 90) t3c,
... etc ...
FROM (
SELECT vm.class,
DATEDIFF(IFNULL(v.retail_date, now()), v.wholesale_date) age
FROM a3s186jg7ffmm0q8.vehicles v
JOIN vehicle_models vm ON vm.id = v.model_id
) subq
GROUP BY class
ORDER BY class;
这个 SUM() 技巧在 MySQL 中有效,因为像 age BETWEEN 0 AND 30
这样的表达式在真时值为 1,在假时值为 0。
问题是:
我在db中有车辆table(这个table的字段不是那么重要),重要的是每辆车都有一个model_id,它指的是vehicle_models table.
车辆型号 table 有 id、class、型号、系列、cm3hp、created_at 和 updated_at 字段。 我需要根据给定标准根据库存中特定型号 class 的车辆数量来定义库存年龄。标准是:0-30 天、31-60 天、61-90 天……360 天以上…… 我不知道它是否足够清楚,但让我试着解释得更好:对于每天的范围,我需要找到给定型号 class 的车辆数量。还有其他标准,但这对我要找出的内容并不重要。为了帮助您更好地理解问题,我将包括结构应该是什么样子的屏幕截图:
我正在使用 MySQL 8.
我写的查询是:
SELECT DISTINCT vm.class,
IFNULL(t1.count, 0) as t1c,
IFNULL(t2.count, 0) as t2c,
IFNULL(t3.count, 0) as t3c,
IFNULL(t4.count, 0) as t4c,
IFNULL(t5.count, 0) as t5c,
IFNULL(t6.count, 0) as t6c,
IFNULL(t7.count, 0) as t7c
FROM vehicle_models vm
LEFT JOIN (
SELECT
vm.class as class,
count(*) as count
FROM a3s186jg7ffmm0q8.vehicles v
JOIN vehicle_models vm
ON vm.id = v.model_id
WHERE
DATEDIFF(IFNULL(v.retail_date, now()), v.wholesale_date) BETWEEN 0 AND 30
GROUP BY vm.class
) t1 ON t1.class = vm.class
*** MORE SAME LEFT JOINS ***
ORDER BY vm.class;
现在,这提供了所需的结果,但我想知道是否有更好的方法来编写此查询,以提高性能和代码结构。
我猜您是在提交一份库存老化报告(这辆车在有人购买之前在经销商处停放了多长时间)。您可以将年龄范围放在顶级 select 中,而不是将每个年龄范围放在单独的子查询中。这将使您的查询更快(子查询有成本)并且更短/更易于阅读。
尝试像这样的嵌套查询。内部查询返回每辆车一行及其老化编号。外部查询聚合它们。
SELECT class,
COUNT(*) total,
SUM(age BETWEEN 0 AND 30) t1c,
SUM(age BETWEEN 31 AND 60) t2c,
SUM(age BETWEEN 61 AND 90) t3c,
... etc ...
FROM (
SELECT vm.class,
DATEDIFF(IFNULL(v.retail_date, now()), v.wholesale_date) age
FROM a3s186jg7ffmm0q8.vehicles v
JOIN vehicle_models vm ON vm.id = v.model_id
) subq
GROUP BY class
ORDER BY class;
这个 SUM() 技巧在 MySQL 中有效,因为像 age BETWEEN 0 AND 30
这样的表达式在真时值为 1,在假时值为 0。