2009-08-27 62 views
1

我有一個表(「轉儲」)的交易,我想列出的總額,按類別分組,每月,如:本月|類別|類別ID |和。涉及的表是這樣的:獲取對不同行的SUM()在MySQL

TABLE dump: 
id INT 
date DATE 
event VARCHAR(100) 
amount DECIMAL(10, 2)
TABLE dump_cat: 
id INT 
did INT (id in dump) 
cid INT (id in categories)
TABLE categories: 
id INT 
name VARCHAR(100)

現在,我嘗試使用該查詢:

SELECT SUBSTR(d.date,1,7) AS month, c.name, c.id AS catid, SUM(d.amount) AS sum 
FROM dump as d, dump_cat as dc, categories AS c 
WHERE dc.did = d.id AND c.id = dc.cid AND SUBSTR(d.date, 1, 7) >= '2008-08' 
GROUP BY month, c.name ORDER BY month;

但對於大多數類別的總和的兩倍大,因爲它應該。我的猜測是,這是因爲連接返回多行,但在字段部分中添加「DISTINCT d.id」沒有任何區別。的查詢返回的內容的示例是:

+---------+--------------------------+-------+-----------+ 
| month | name      | catid | sum  | 
+---------+--------------------------+-------+-----------+ 
| 2008-08 | Cash      | 21 | -6200.00 | 
| 2008-08 | Gas      |  8 | -2936.19 | 
| 2008-08 | Rent      |  1 | -15682.00 |

其中作爲

SELECT DISTINCT d.id, d.amount FROM dump AS d, dump_cat AS dc 
WHERE d.id = dc.did AND SUBSTR(d.date, 1, 7) ='2008-08' AND dc.cid = 21;

返回

+------+----------+ 
| id | amount | 
+------+----------+ 
| 3961 | -600.00 | 
| 2976 | -200.00 | 
| 2967 | -400.00 | 
| 2964 | -200.00 | 
| 2957 | -300.00 | 
| 2962 | -1400.00 | 
+------+----------+

這樣總計3100,一半以上列出的總和。如果我從最後一個查詢中刪除「DISTINCT d.id」,則每行都列出兩次。我認爲這是問題,但我需要幫助來弄清楚如何解決它。提前致謝。

補充:如果我收集轉儲和dump_cat表爲一體,具有

CREATE table dumpwithcat SELECT DISTINCT d.id, d.date, d.event, d.amount, dc.cid 
    FROM dump AS d, dump_cat AS c WHERE c.did = d.id;

,並做了查詢該表,一切工作正常使用正確的總和。有沒有辦法在原始查詢中做到這一點,與子查詢或類似的東西?

+0

如果您取出SUM和GROUP BY並選擇金額,您是否看到重複的記錄? – 2009-08-27 19:20:37

+0

Eric:是的。我如何擺脫它們? :) – Par 2009-08-27 19:52:29

+0

如果你加入dump和dump_cat你會得到任何重複嗎?如何dump_cat和類別? – 2009-08-27 20:26:30

回答

2

這樣總計的3100,總和的一半以上所列。如果我從最後一個查詢中刪除「DISTINCT d.id」,則每行都列出兩次。

雖然您可以在每個轉儲只有一類,因此你必須在每dump_cat轉儲有多個。你應該考慮定義UNIQUE約束,以確保每對did只有一個行存在,cid

ALTER TABLE dump_cat ADD CONSTRAINT UNIQUE (did, cid); 

我預測這個聲明將在你的表失敗鑑於目前的數據。當這些列已經包含重複項時,它不能創建唯一約束!

您可以刪除重複這種方式,例如:

DELETE dc1 FROM dump_cat dc1 JOIN dump_cat dc2 USING (did, cid) 
WHERE dc1.id > dc2.id; -- only delete the second duplicate entry 

編輯:順便說一句,不要記住我的問題接受,直到您已驗證我是正確的! :-)

您可以驗證有實際上的複印件,我建議使用查詢類似如下:

SELECT did, COUNT(*) 
FROM dump_cat 
GROUP BY did 
HAVING COUNT(*) > 1; 

另一種可能性:你有多個類別名稱相同? (抱歉,我第一次嘗試在此查詢是錯誤的,這裏是一個編輯的版本)

SELECT c.name, GROUP_CONCAT(c.id) AS cat_id_list, COUNT(*) AS c 
FROM category c 
GROUP BY c.name 
HAVING COUNT(*) > 1; 

FWIW,我做了測試DELETE命令我表明:

INSERT INTO dump_cat (did, cid) VALUES (1, 2), (3,4), (3,4); -- duplicates! 

DELETE dc1 FROM dump_cat dc1 JOIN dump_cat dc2 USING (did, cid) WHERE dc1.id > dc2.id 
Query OK, 1 row affected (0.00 sec) 

PS:這與您的問題相切,但DISTINCT查詢修飾符始終適用於整行,而不僅僅是第一列。這是很多SQL程序員的常見誤解。

+0

非常感謝!我沒有注意到這一點,數據導入算法中出現了錯誤。 現在,刪除重複的SQL不起作用(查詢OK,0行受到影響),是否有另一種方式來寫? – Par 2009-08-27 20:38:38

+0

受影響的行不意味着它沒有工作,這意味着它沒有發現任何重複。所以也許我的理論認爲你有重複是錯誤的。 – 2009-08-27 20:40:15

+0

我確實使用了「select did,cid,count(*)from dump_cat group by did,cid count(*)> 1;」。仍然刪除沒有幫助。但我用「create table dump_cat_unique SELECT distinct * FROM dump_cat;」來修復它然後丟棄舊的dump_cat並重命名新的。現在一切都很好,再次感謝。 – Par 2009-08-27 20:49:55

1

在第一次考試,它看起來像你對我可能有bgetween轉儲和Dump_Cat參照完整性約束倒退。

燦交易(在轉儲)是在多個類別?如果不是,那麼交易表(轉儲)不應該指定每個交易在哪個類別,而不是更多的方式?即應該在轉儲表中存在CatId而不是Cat表中的DumpId?

如果交易可以在多個類別,那麼你的數據結構是正確的,你butthen難免會加倍(或乘)計數交易在任何聚集查詢金額,因爲交易金額其實是在多個類別。

+0

我打算使用多個類別,因此使用dump_cat的數據庫方案負責轉儲和類別之間的關係。但是我還沒有,所以我查詢的數據在轉儲中每行只有一個類別。 – Par 2009-08-27 19:58:28

1

如果轉儲記錄可以在多個類別中,它們將影響所有該類別在該月份的行。

對此的一個解決方案是也爲每個轉儲記錄提取一個COUNT()類別,並將其用作各個數額的除數。因此,轉儲記錄所屬的所有類別都會自動以一定比例自動分配金額,從而保持整體總額的完整性。

像這樣的東西(抱歉,MySQL是不是我每天的RDBMS,不知道確切的語法):

SELECT SUBSTR(d.date,1,7) AS month, c.name, c.id AS catid, 
    SUM(d.amount/(SELECT COUNT(*) FROM dump_cat dc2 WHERE dc2.did=d.id)) AS sum 
FROM dump as d, dump_cat as dc, categories AS c 
WHERE dc.did = d.id AND c.id = dc.cid AND SUBSTR(d.date, 1, 7) >= '2008-08' 
GROUP BY month, c.name ORDER BY month; 
+0

我可以看到你的後,但我還沒有添加任何轉儲記錄到多個類別。轉儲中的每條記錄只有一個類別。 – Par 2009-08-27 20:01:21

+0

此外,真的會影響sum()按類別分組嗎?我只能看到,它會使該月的總金額過大,但不是每個類別的總和,因爲轉儲記錄不會在類別內重複,對嗎? – Par 2009-08-27 20:20:27

1

您可以採取幾乎任何查詢,如您用來創建不同表格的查詢,並選擇該查詢。只要給查詢一個「表名」即可。

SELECT SUBSTR(d_dc.date,1,7) AS month, c.name, c.id AS catid, SUM(d_dc.amount) AS sum 
FROM (SELECT DISTINCT d.id, d.date, d.event, d.amount, dc.cid 
    FROM dump AS d, dump_cat AS dc WHERE dc.did = d.id 
    WHERE SUBSTR(d.date, 1, 7) >= '2008-08') AS d_dc 
JOIN categories AS c ON d_dc.cid=c.id 
GROUP BY month, c.name ORDER BY month 

這可能不是做你的查詢最有效的方式,我可能已經得到了一些表別名錯的,但應該給你如何做到這一點的想法。

+0

很高興知道,謝謝。 – Par 2009-08-27 20:54:53