簡體   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