我有两张桌子:
table: transaction:
====================
id billed_date amount
1 2016-09-30 5
2 2016-10-04 15
3 2016-10-06 10
table: report_date
====================
transaction_id report_date
1 2016-10-01
我想:
然后我写道:
第一个:
SELECT
sum(t.amount),
CASE WHEN d.report_date IS NOT NULL THEN d.report_date ELSE t.billed_date END AS new_date
FROM
transaction t LEFT JOIN report_date d ON t.id = d.transaction_id
WHERE new_date BETWEEN '2016-10-01' AND '2016-10-30'
第二个:
SELECT sum(amount) FROM
(SELECT t.amount,
CASE WHEN d.report_date IS NOT NULL THEN d.report_date ELSE t.billed_date END AS date
FROM transaction t LEFT JOIN report_date d ON t.id = d.transaction_id
) t
WHERE t.date BETWEEN '2016-10-01' AND '2016-10-30'
结果:
第一个:
第二个:
任何人都可以帮助我?
答案 0 :(得分:1)
我终于在哥哥的帮助下找到了解决方案:
SELECT sum(amount)
FROM transaction t LEFT JOIN report_date d ON id = transaction_id
WHERE (report_date BETWEEN '2016-10-01' AND '2016-10-30') OR (report_date IS NULL AND billed_date BETWEEN '2016-10-01' AND '2016-10-30')
谢谢你关心我!
答案 1 :(得分:1)
首先 - 部分
CASE WHEN d.report_date IS NOT NULL THEN d.report_date ELSE t.billed_date END
可以缩写为
COALESCE(d.report_date, t.billed_date)
或
IFNULL(d.report_date, t.billed_date)
在第一个查询中,您在WHERE子句中使用了列别名,这是不允许的。您可以通过将别名后面的表达式移动到WHERE子句来修复它:
SELECT sum(t.amount)
FROM transaction t LEFT JOIN report_date d ON t.id = d.transaction_id
WHERE COALESCE(d.report_date, t.billed_date) BETWEEN '2016-10-01' AND '2016-10-30'
这与您自己的解决方案几乎相同。
你的第二个查询很慢,因为MySQL必须将子查询结果(30K行)存储到临时表中。试图对其进行优化,最终会得到相同的解决方案。
但是,如果您在transaction.billed_date
和report_date.report_date
上有索引,则此查询仍然无法使用它们。要使用索引,可以将查询拆分为两部分:
包含报告的条目(将使用report_date.report_date
索引):
SELECT sum(amount)
FROM transaction t JOIN report_date d ON id = transaction_id
WHERE d.report_date BETWEEN '2016-10-01' AND '2016-10-30'
没有报告的条目(将使用transaction.billed_date
索引):
SELECT sum(amount)
FROM transaction t LEFT JOIN report_date d ON id = transaction_id
WHERE d.report_date IS NULL AND t.billed_dateBETWEEN '2016-10-01' AND '2016-10-30'
两个查询都可以使用索引。您只需要对结果求和,也可以将两个查询结合起来:
SELECT (
SELECT sum(amount)
FROM transaction t JOIN report_date d ON id = transaction_id
WHERE d.report_date BETWEEN '2016-10-01' AND '2016-10-30'
) + (
SELECT sum(amount)
FROM transaction t LEFT JOIN report_date d ON id = transaction_id
WHERE d.report_date IS NULL AND t.billed_dateBETWEEN '2016-10-01' AND '2016-10-30'
) AS sum_amount
答案 2 :(得分:0)
填充table: report_date
是否包含table: transaction:
案例中缺少的值?
SELECT id FROM report_date WHERE report_date BETWEEN '2016-10-01' AND '2016-10-30';
INSERT INTO report_date SELECT id, billed_date FROM transaction WHERE billed_date BETWEEN '2016-10-01' AND '2016-10-30' AND id NOT IN (ids_from previous_query);
SELECT sum(t.amount) FROM transaction LEFT JOIN report_date d ON (t.id = d.transaction_id) WHERE d.report_date BETWEEN '2016-10-01' AND '2016-10-30';
答案 3 :(得分:0)
您的第二个查询是正确的,无需重新编写查询。但我有一件事要告诉你,在处理数千/数百万条记录时,这对你有很大的帮助。我们也关注其他一些事情。因为当您的表包含大量数据(数千和数百万)记录时,执行查询需要时间。它也可能导致锁定,可能是查询锁或数据库消失的问题。要避免此问题,您只需创建一列的 INDEX 即可。在该列上创建 INDEX ,对where子句执行/使用。与您的情况类似,您可以在交易表的 billed_date 列中创建 INDEX 。因为您的结果基于交易表。有关如何在mysql / phpmyadmin中创建索引的更多详细信息,您可以参考此http://www.yourwebskills.com/dbphpmyadmintable.php链接。
我在某个时间点遇到过同样的问题,然后我在列上创建了 INDEX 。现在我使用mysql处理数百万条记录。