在多行上使用 LEFT JOIN 简化我的 SQL
Simplifying my SQL with LEFT JOIN on multiple lines
我现在对 MySQL 和高效查询相当有经验,但仍然 运行 遇到问题...
我有两个 table,"invoices" 和 "salesRecords" 发票 table 包含发票的基本概述,销售记录按以下方式细分特定信息行关于购买的物品的行。
为简单起见,我们假设 table 如下所示:
发票
id | repairCharge | shippingCharge | total
1 | 28.95 | 0 | 30.45
2 | 10.00 | 8.50 | 29.50
//注意;总计列包括销售记录中显示的项目
销售记录
invNo | itemNo | price | quantity | discount |
1 | 123 | 1.50 | 1 | 0 |
2 | 121 | 6.50 | 1 | 1.5 |
2 | 128 | 5.50 | 1 | 0 |
我想获取一个日期段内售出商品的总价值、人工费和运费,所以我需要:
- 对 Invoices 中的所有行求和 Table
JOIN
(左?)SalesRecords Table ON invNo and SUM ((price-discount)*quantity)
- 为日期期间使用 WHERE 子句
我马上写这个SQL:
SELECT SUM((sr.price-sr.discount)*sr.quantity) as income,
SUM(i.repairCharge) as labour,
SUM(i.shippingCharge) as carriage
FROM invoices i
LEFT JOIN salesRecords sr ON sr.invNo=i.id
WHERE i.dateTime BETWEEN 1431647999 AND 1434360348`
这是错误的
因为,对于具有多个项目行的任何发票,我得到两个 table 的多个实例,因此 repairCharge
和 shippingCharge
值加倍或加倍等取决于该发票上购买了多少产品线。
所以,我四处乱逛并想出了一个解决方案...但它非常丑陋并且可能效率低下:
SELECT SUM(income) as income,
SUM(labour) as labour,
SUM(carriage) as carriage
FROM (SELECT (SELECT SUM((price-discount)*quantity)
FROM salesRecords
where invno=i.id
GROUP BY invNo) as income,
SUM(i.repairCharge) as labour,
SUM(i.shippingCharge) as carriage
FROM invoices i
WHERE i.dateTime BETWEEN 1434326474 AND 1434361694
GROUP BY id
) totals
任何人都可以建议简化并提高效率的最佳方法吗?
试试这个:
select sum(labour) as labour,
sum(carriage) as carriage,
sum(income) as income
from( select sum(i.repairCharge) as labour,
sum(i.shippingCharge) as carriage,
coalesce(sum((sr.price - sr.discount) * sr.quantity), 0) as income
from Invoices i
left join SalesRecords sr on i.id = sr.invNo
group by i.id)t
就大多数其他 DBMS 的易读性和性能而言,我个人只会在子查询中汇总销售记录:
SELECT SUM(COALESCE(sr.Income, 0)) AS Income,
SUM(i.repairCharge) AS Labour,
SUM(i.shippingCharge) AS Carriage
FROM Invoices AS i
LEFT JOIN
( SELECT InvNo, SUM((price-discount)*quantity) AS Income
FROM SalesRecords
GROUP BY InvNo
) AS sr
ON sr.InvNo = i.ID
WHERE i.dateTime BETWEEN 1434326474 AND 1434361694;
MySQL 在子查询上使用中间具体化(据我所知),如果这样做可能会对上述查询产生不利影响,因为它会首先汇总 SalesRecords
中的所有记录并在对发票日期应用过滤器之前将结果存储在散列 table 中,因此您的工作版本,但使用 JOIN 而不是相关子查询可能会执行得更好:
SELECT SUM(COALESCE(i.Income, 0)) AS Income,
SUM(i.repairCharge) AS Labour,
SUM(i.shippingCharge) AS Carriage
FROM ( SELECT i.ID,
i.repairCharge,
i.shippingCharge,
SUM((sr.price - sr.discount) * sr.quantity) AS Income
FROM Invoices AS i
LEFT JOIN SalesRecords AS sr
ON sr.InvNo = i.ID
WHERE i.dateTime BETWEEN 1434326474 AND 1434361694
GROUP BY i.ID, i.repairCharge, i.ShippingCharge
) AS i;
我现在对 MySQL 和高效查询相当有经验,但仍然 运行 遇到问题...
我有两个 table,"invoices" 和 "salesRecords" 发票 table 包含发票的基本概述,销售记录按以下方式细分特定信息行关于购买的物品的行。
为简单起见,我们假设 table 如下所示:
发票
id | repairCharge | shippingCharge | total
1 | 28.95 | 0 | 30.45
2 | 10.00 | 8.50 | 29.50
//注意;总计列包括销售记录中显示的项目
销售记录
invNo | itemNo | price | quantity | discount |
1 | 123 | 1.50 | 1 | 0 |
2 | 121 | 6.50 | 1 | 1.5 |
2 | 128 | 5.50 | 1 | 0 |
我想获取一个日期段内售出商品的总价值、人工费和运费,所以我需要:
- 对 Invoices 中的所有行求和 Table
JOIN
(左?)SalesRecords Table ON invNo and SUM ((price-discount)*quantity)- 为日期期间使用 WHERE 子句
我马上写这个SQL:
SELECT SUM((sr.price-sr.discount)*sr.quantity) as income,
SUM(i.repairCharge) as labour,
SUM(i.shippingCharge) as carriage
FROM invoices i
LEFT JOIN salesRecords sr ON sr.invNo=i.id
WHERE i.dateTime BETWEEN 1431647999 AND 1434360348`
这是错误的
因为,对于具有多个项目行的任何发票,我得到两个 table 的多个实例,因此 repairCharge
和 shippingCharge
值加倍或加倍等取决于该发票上购买了多少产品线。
所以,我四处乱逛并想出了一个解决方案...但它非常丑陋并且可能效率低下:
SELECT SUM(income) as income,
SUM(labour) as labour,
SUM(carriage) as carriage
FROM (SELECT (SELECT SUM((price-discount)*quantity)
FROM salesRecords
where invno=i.id
GROUP BY invNo) as income,
SUM(i.repairCharge) as labour,
SUM(i.shippingCharge) as carriage
FROM invoices i
WHERE i.dateTime BETWEEN 1434326474 AND 1434361694
GROUP BY id
) totals
任何人都可以建议简化并提高效率的最佳方法吗?
试试这个:
select sum(labour) as labour,
sum(carriage) as carriage,
sum(income) as income
from( select sum(i.repairCharge) as labour,
sum(i.shippingCharge) as carriage,
coalesce(sum((sr.price - sr.discount) * sr.quantity), 0) as income
from Invoices i
left join SalesRecords sr on i.id = sr.invNo
group by i.id)t
就大多数其他 DBMS 的易读性和性能而言,我个人只会在子查询中汇总销售记录:
SELECT SUM(COALESCE(sr.Income, 0)) AS Income,
SUM(i.repairCharge) AS Labour,
SUM(i.shippingCharge) AS Carriage
FROM Invoices AS i
LEFT JOIN
( SELECT InvNo, SUM((price-discount)*quantity) AS Income
FROM SalesRecords
GROUP BY InvNo
) AS sr
ON sr.InvNo = i.ID
WHERE i.dateTime BETWEEN 1434326474 AND 1434361694;
MySQL 在子查询上使用中间具体化(据我所知),如果这样做可能会对上述查询产生不利影响,因为它会首先汇总 SalesRecords
中的所有记录并在对发票日期应用过滤器之前将结果存储在散列 table 中,因此您的工作版本,但使用 JOIN 而不是相关子查询可能会执行得更好:
SELECT SUM(COALESCE(i.Income, 0)) AS Income,
SUM(i.repairCharge) AS Labour,
SUM(i.shippingCharge) AS Carriage
FROM ( SELECT i.ID,
i.repairCharge,
i.shippingCharge,
SUM((sr.price - sr.discount) * sr.quantity) AS Income
FROM Invoices AS i
LEFT JOIN SalesRecords AS sr
ON sr.InvNo = i.ID
WHERE i.dateTime BETWEEN 1434326474 AND 1434361694
GROUP BY i.ID, i.repairCharge, i.ShippingCharge
) AS i;