2011-08-27 23 views
0

我與列編號,tDate,描述,退幣,卡希銀行交易表中的多個時間相加行。我想看看我怎麼花我的錢,特別是在亞馬遜和一個叫梅佐店,所以我想這樣的結果:SQL避免根據LIKE表達

Month Amazon Mazo Total 
1  100  200 300 

我嘗試這樣的:

SELECT 
    MONTH(tDate) AS Month, 
    SUM(IF(description LIKE '%amazon%',cashOut,0)) AS Amazon, 
    SUM(IF(description LIKE '%mazo%',cashOut,0)) AS Mazo, 
    SUM(cashOut) AS Total 
FROM `transactions` 
GROUP BY Month 

但是,我得到了以下:

Month Amazon Mazo Total 
1  100  300 300 

的問題與此SQL查詢是,「梅佐」 -transactions總和是錯誤的,因爲它也增加了「亞馬遜」的交易。

我想要的交易選擇,總結相互排斥或類似的東西,使每一筆交易只以上的款項之一的一部分(而不是訴諸PHP或類似)。 (我的表格包含比這更多的數據,並且我有很多搜索條件,所以使用'%mazo%'作爲搜索詞是不夠的。我需要一個通用的解決方案來解決這個問題。)

有人有建議嗎?表及其數據的

詳情:

CREATE TABLE `transactions` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, 
`tDate` date NOT NULL, 
`description` varchar(200) NOT NULL, 
`cashOut` decimal(10,0) NOT NULL, 
`cashIn` decimal(10,0) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB 

INSERT INTO `transactions` (`id`, `tDate`, `description`, `cashOut`, `cashIn`) VALUES 
(1, '2010-01-05', 'amazon', '100', '0'), 
(4, '2010-01-15', 'mazo', '200', '0'); 

回答

2

您可以通過在內部查詢標記每行,然後過濾與創建互斥組:

SELECT 
    MONTH(tDate) AS Month, 
    SUM(IF(flag = 'amazon', cashOut, 0)) AS Amazon, 
    SUM(IF(flag = 'mazo', cashOut, 0)) AS Mazo, 
    SUM(IF(flag = 'other', cashOut, 0)) AS Other, 
    SUM(cashOut) AS Total 
FROM (
    SELECT tDate, cashOut, 
     CASE 
      WHEN description LIKE '%amazon%' THEN 'amazon' 
      WHEN description LIKE '%mazo%' THEN 'mazo' 
      ELSE 'other' 
     END AS flag 
    FROM transactions 
) x 
GROUP BY Month 

這樣,你永遠不會兩次計數同一個事務如果某個交易將匹配多個關鍵字。如果你不想重複兩次相同的關鍵字查詢,並可以用一個列表看起來像住:

Month What  Sum 
1  amazon 100 
2  mazo  200 

那麼你可以使用:

SELECT 
    MONTH(tDate) AS Month, 
    flag AS What, 
    SUM(cashOut) AS Total 
FROM (
    SELECT tDate, cashOut, 
     CASE 
      WHEN description LIKE '%mazo%' THEN 'mazo' 
      WHEN description LIKE '%amazon%' THEN 'amazon' 
      ELSE 'other' 
     END AS flag 
    FROM transactions 
) x 
GROUP BY Month, flag 
+0

正是我需要的,非常感謝! (至於第二個建議,我不會這樣做,因爲我需要知道每個搜索關鍵字每個月的總和。) –

1

您正在搜索包含mazo字符串。如果你只是想梅佐,變化:

SUM(IF(description LIKE '%mazo%',cashOut,0)) AS Mazo, 

SUM(IF(description = 'mazo',cashOut,0)) AS Mazo, 

編輯:在回答您的意見,您可以使用正則表達式[[:<:]]搜索word boundaries

SUM(IF(description REGEXP '[[:<:]]mazo[[:>:]]',cashOut,0)) AS Mazo, 
+0

不,我要包含字符串梅佐。我看到,我沒有提到交易的描述通常是一些更長的字符串,如「53,12紐約梅佐布拉布拉」。 –

+0

@Yngvar克里斯坦森:也許這是最好的搜索詞的邊界,其中匹配字符串開始的,空格,逗號等。添加示例以回答。 – Andomar

+0

的正則表達式仍然沒有做出互相排斥的結果。我不想多次交易一筆交易。 –

0

使用=有確切的文本,而不是like和簡單地失去了IF。試試這個:

SELECT 
    MONTH(tDate) AS Month, 
    SUM((description = 'Amazon') * cashOut) AS Amazon, 
    SUM((description = 'Mazo') * cashOut) AS Mazo, 
    SUM(cashOut) AS Total 
FROM `transactions` 
GROUP BY Month 
1
SELECT 
    MONTH(tDate) AS Month, 
    SUM(IF(description LIKE '%amazon%',cashOut,0)) AS Amazon, 
    SUM(IF(description LIKE '%mazo%' AND description NOT LIKE '%amazon%',cashOut,0)) AS Mazo, 
    SUM(cashOut) AS Total 
FROM `transactions` 
GROUP BY Month 
+0

這起作用。但是,假設我有50個搜索詞,例如amazon和mazo,那麼SQL將會非常大。有沒有更一般或更優雅的方式來做到這一點? –

+0

我建議在插入時在列中添加某種冗餘標識符。這意味着計算只能在插入時進行一次。例如:你爲亞馬遜,'MAZO'等添加'AMZ'然後你只需要進行平等比較。如果你想更進一步,你可以使用整數標識符,因爲比較會更快(1 = Amazon,2 = Mazo等) – CyberDude

+0

如果你有50個搜索詞,那麼最好創建一個供應商表,並在每次交易中存儲供應商代碼。然後將供應商的費用加起來是微不足道的。 –