简体   繁体   English

Mysql用其他列值替换列值

[英]Mysql replace column value with other column value

I have 2 tables: 我有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

I want: 我想要:

  • Create a report which sum all transactions's amount in October 2016 创建一份报告,汇总2016年10月所有交易的金额
  • Base on report date, not billed date 根据报告日期而非收费日期
  • When report date is not set, it's base on billed_date 如果未设置报告日期,则基于billed_date
  • In above example, I want result is 30 (not 25) 在上面的例子中,我想结果是30(不是25)

Then I write: 然后我写道:

The First: 首先:

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'

The Second: 第二:

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'

Result: 结果:

The First: 首先:

  • Unknown column 'new_date' in 'where clause' 'where子句'中的未知列'new_date'
  • If I replace 'new_date' by 'date': result = 25 (exclude id=1) 如果我将'new_date'替换为'date':result = 25(不包括id = 1)

The Second: 第二:

  • result = 30 => Correct, but in my case, when transaction table have about 30k records, the process is too slow. result = 30 =>正确,但在我的情况下,当事务表有大约30k记录时,过程太慢。

Anybody can help me? 有人可以帮帮我吗?

I finally find out the solution with the help from my brother: 我终于在哥哥的帮助下找到了解决方案:

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

Thank you for caring me! 谢谢你关心我!

First of all - the part 首先 - 部分

CASE WHEN d.report_date IS NOT NULL THEN d.report_date ELSE t.billed_date END

can be written shorter as 可写得更短

COALESCE(d.report_date, t.billed_date)

or as 或者作为

IFNULL(d.report_date, t.billed_date)

In your first query you are using a column alias in the WHERE clause, wich is not allowed. 在第一个查询中,您在WHERE子句中使用了列别名,这是不允许的。 You can fix it by moving the expression behind the alias to the WHERE clause: 您可以通过将别名后面的表达式移动到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'

This is almost the same as your own solution. 这与您自己的解决方案几乎相同。

Your second query is slow because MySQL has to store the subquery result (30K rows) into a temporary table. 您的第二个查询很慢,因为MySQL必须将子查询结果(30K行)存储到临时表中。 Trying to optimize it, you will end up with the same solution above. 试图优化它,你将最终得到相同的解决方案。

However if you have indexes on transaction.billed_date and report_date.report_date this query still can not use them. 但是,如果您在transaction.billed_datereport_date.report_date上有索引,则此查询仍然无法使用它们。 In order to use the indexes, you can split the query into two parts: 要使用索引,可以将查询拆分为两部分:

Entries with a report (will use report_date.report_date index): 包含报告的条目(将使用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'

Entries without a report (will use transaction.billed_date index): 没有报告的条目(将使用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'

Both queries can use an index. 两个查询都可以使用索引。 You just need to sum the results, wich can also be done combining the two queries: 您只需要对结果求和,也可以将两个查询结合起来:

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

Is fill table: report_date with absent values from table: transaction: the case? 填表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';

Your Second Query is correct,no need to re-write query. 您的第二个查询是正确的,无需重新编写查询。 But I have one thing to tell you, which will help you a lot when dealing with thousand/millions of records. 但我有一件事要告诉你,在处理数千/数百万条记录时,这对你有很大的帮助。 We have focus on some other things too. 我们也关注其他一些事情。 Because when your table contains large amount of data(in thousands and millions) of records then it takes time to execute query. 因为当您的表包含大量数据(数千和数百万)记录时,执行查询需要时间。 It may causes locking also, might be query lock or database gone away kind of issue. 它也可能导致锁定,可能是查询锁或数据库消失的问题。 To avoid this issue,you just create INDEX of one column. 要避免此问题,您只需创建一列的INDEX Create INDEX on that column which act/use on where clauses. 在该列上创建INDEX ,它在where子句上执行/使用。 Like in your case you can create INDEX on billed_date column from transaction table. 与您的情况类似,您可以在事务表中的billed_date列上创建INDEX Because your result is based on transaction table. 因为您的结果基于事务表。 For more details how to create index in mysql/phpmyadmin you can take reference from this http://www.yourwebskills.com/dbphpmyadmintable.php link. 有关如何在mysql / phpmyadmin中创建索引的更多详细信息,请参阅此http://www.yourwebskills.com/dbphpmyadmintable.php链接。

I had been faced same issue at some point of time then I created INDEX on column. 在某些时候我遇到过同样的问题然后我在列上创建了INDEX Now I am dealing with millions of records using mysql. 现在我使用mysql处理数百万条记录。

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

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