【发布时间】:2021-04-13 22:50:33
【问题描述】:
我有这个表格方案(删除了不重要的列):
我正在为此编写 REST API。我需要在某个日期范围内销售分页产品。
这对我来说不是问题,但我还需要按产品代码或销售数量对它们进行排序。后者对我来说是个问题。
我的想法是查询产品,然后使用子查询来查找按日期过滤的sold_products 并将结果销售数量相加。然后按那个总和排序。
这行得通,但这确实效率不高。对于每一个产品,我必须总结它的销售产品,最后我只得到 10 个结果(因为我使用的是分页)。我最近一次使用这种方式的尝试耗时 6.5 秒,所以......
我的第二个想法是从另一边走。查询 sold_products,按 product_id 分组,过滤它们,然后找到它的父母。
这很好用,就是这样,但有一个问题 - 我没有得到尚未售出的产品。
我该怎么做?我想我不需要确切的查询,只要知道我应该如何处理就足够了。
提前谢谢你!
编辑:
以 CSV 格式输入数据(希望可以这样):
产品:
| id | code |
|---|---|
| 1 | A11 |
| 2 | A12 |
| 3 | B11 |
product_variant:
| id | product_id | code | initial_quantity |
|---|---|---|---|
| 1 | 1 | A11-1 | 50 |
| 2 | 1 | A11-2 | 50 |
| 3 | 1 | A11-3 | 80 |
| 4 | 2 | A12-1 | 20 |
| 5 | 2 | A12-2 | 30 |
| 6 | 2 | A12-3 | 80 |
| 7 | 2 | A12-4 | 90 |
| 8 | 3 | B11-1 | 70 |
| 9 | 3 | B11-2 | 70 |
已售产品:
| id | product_id | product_variant | quantity | date |
|---|---|---|---|---|
| 1 | 1 | 1 | 20 | 2021-04-01 |
| 2 | 1 | 1 | 15 | 2021-04-01 |
| 3 | 1 | 2 | 15 | 2021-04-04 |
| 4 | 1 | 3 | 10 | 2021-04-05 |
| 5 | 1 | 3 | 19 | 2021-04-07 |
| 6 | 2 | 4 | 11 | 2021-04-07 |
| 7 | 2 | 5 | 12 | 2021-04-08 |
| 8 | 2 | 7 | 15 | 2021-04-10 |
| 9 | 2 | 7 | 15 | 2021-04-10 |
结果:
| product_id | product_code | initial_quantity | sold_quantity |
|---|---|---|---|
| 1 | A11 | 180 | 79 |
| 2 | A12 | 220 | 53 |
| 3 | B11 | 140 | 0 or NULL |
销售日期范围 2021-04-07 到 2021-04-08 并按 sold_quantity asc 排序时的结果:
| product_id | product_code | initial_quantity | sold_quantity |
|---|---|---|---|
| 3 | B11 | 140 | 0 or NULL |
| 1 | A11 | 180 | 19 |
| 2 | A12 | 220 | 23 |
示例数据 SQL:
CREATE TABLE product(id INT, code VARCHAR(25));
CREATE TABLE product_variant(id INT, product_id INT, code VARCHAR(25), initial_quantity INT);
CREATE TABLE sold_product(id INT, product_id INT, product_variant_id INT, quantity INT, date_time DATETIME);
INSERT INTO product VALUES(1,'A11');
INSERT INTO product VALUES(2,'A12');
INSERT INTO product VALUES(3,'B11');
INSERT INTO product_variant VALUES(1,1,'A11-1',50);
INSERT INTO product_variant VALUES(2,1,'A11-2',50);
INSERT INTO product_variant VALUES(3,1,'A11-3',80);
INSERT INTO product_variant VALUES(4,2,'A12-1',20);
INSERT INTO product_variant VALUES(5,2,'A12-2',30);
INSERT INTO product_variant VALUES(6,2,'A12-3',80);
INSERT INTO product_variant VALUES(7,2,'A12-4',90);
INSERT INTO product_variant VALUES(8,3,'B11-1',70);
INSERT INTO product_variant VALUES(9,3,'B11-2',70);
INSERT INTO sold_product VALUES(1,1,1,20,'2021-04-01');
INSERT INTO sold_product VALUES(2,1,1,15,'2021-04-01');
INSERT INTO sold_product VALUES(3,1,2,15,'2021-04-04');
INSERT INTO sold_product VALUES(4,1,3,10,'2021-04-05');
INSERT INTO sold_product VALUES(5,1,3,19,'2021-04-07');
INSERT INTO sold_product VALUES(6,2,4,11,'2021-04-07');
INSERT INTO sold_product VALUES(7,2,5,12,'2021-04-08');
INSERT INTO sold_product VALUES(8,2,7,15,'2021-04-10');
INSERT INTO sold_product VALUES(9,2,7,15,'2021-04-10');
第一个想法:
SELECT p.id, p.code,
(
SELECT SUM(v.initial_quantity)
FROM product_variant AS v
WHERE p.id = v.product_id
) AS initial_quantity,
(
SELECT SUM(s.quantity)
FROM sold_product AS s
WHERE p.id = s.product_id
) AS sold_quantity
FROM product AS p
ORDER BY sold_quantity;
第二个想法:
SELECT p.id, p.code,
(
SELECT SUM(v.initial_quantity)
FROM product_variant AS v
WHERE p.id = v.product_id
) AS initial_quantity,
SUM(s.quantity) AS sold_quantity
FROM sold_product AS s
INNER JOIN product AS p ON s.product_id = p.id
GROUP BY p.code, p.id,
(
SELECT SUM(v.initial_quantity)
FROM product_variant AS v
WHERE p.id = v.product_id
)
ORDER BY sold_quantity;
编辑:JOIN 尝试,返回单个结果以及所有已售数量的总和
SELECT p.id, p.code,
(
SELECT SUM(v.initial_quantity)
FROM product_variant AS v
WHERE p.id = v.product_id
) AS initial_quantity,
SUM(s.quantity) AS sold_quantity
FROM product AS p
JOIN sold_product AS s ON p.id = s.product_id
ORDER BY sold_quantity;
【问题讨论】:
-
实际上,我打算在那里提出与您的第一个想法类似的建议。我读到你对那个有问题.. 两个问题,对吗?一个是“最后我只取10个结果(因为我使用分页)”,另一个是关于性能。我不太了解第一个问题,我想对于第二个问题,为了提高性能,您可以尝试将
SELECT中的子查询转换为JOIN并比较性能......当然还有正确的索引,它会运行得更快 -
有多少种不同的product_id?
-
我刚刚在生产数据库上尝试过,我写的查询花了 18.5 秒。当我删除
sold_quantity子查询时,只用了 0.08 秒。 -
product中有近 4 000 行,但在生产中我也有类似“全局过滤器”(WHERE product.catalog = 1),这将其缩小到 600 条记录。sold_product中有近 20 000 行,但并非所有这些都与我的 600 条产品记录相关联。 -
我忘了回答:“我只取 10 个结果”并不是一个问题,我只是说我需要对所有行进行那些昂贵的计算才能得到 10 个他们。但我仍然需要做一些,以便我可以按已售出排序。而且我还尝试用 JOIN 替换子查询,但它对我不起作用。它返回所有已售数量的单个结果总和。也许我做错了,我的尝试更新了问题。