繁体   English   中英

Mysql用其他列值替换列值

[英]Mysql replace column value with other column value

我有2张桌子:

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

我想要:

  • 创建一份报告,汇总2016年10月所有交易的金额
  • 根据报告日期而非收费日期
  • 如果未设置报告日期,则基于billed_date
  • 在上面的例子中,我想结果是30(不是25)

然后我写道:

首先:

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'

结果:

首先:

  • 'where子句'中的未知列'new_date'
  • 如果我将'new_date'替换为'date':result = 25(不包括id = 1)

第二:

  • result = 30 =>正确,但在我的情况下,当事务表有大约30k记录时,过程太慢。

有人可以帮帮我吗?

我终于在哥哥的帮助下找到了解决方案:

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')

谢谢你关心我!

首先 - 部分

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_datereport_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

填表table: report_date缺少值table: transaction: case?

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';

您的第二个查询是正确的,无需重新编写查询。 但我有一件事要告诉你,在处理数千/数百万条记录时,这对你有很大的帮助。 我们也关注其他一些事情。 因为当您的表包含大量数据(数千和数百万)记录时,执行查询需要时间。 它也可能导致锁定,可能是查询锁或数据库消失的问题。 要避免此问题,您只需创建一列的INDEX 在该列上创建INDEX ,它在where子句上执行/使用。 与您的情况类似,您可以在事务表中的billed_date列上创建INDEX 因为您的结果基于事务表。 有关如何在mysql / phpmyadmin中创建索引的更多详细信息,请参阅此http://www.yourwebskills.com/dbphpmyadmintable.php链接。

在某些时候我遇到过同样的问题然后我在列上创建了INDEX 现在我使用mysql处理数百万条记录。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM