[英]Getting SUM() on distinct rows in mysql
我有一個包含交易的表格(“轉儲”),我想按月列出按類別分組的總金額,例如: 分類| 分類ID | 和。 涉及的表如下所示:
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和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;
並在該表上進行查詢,一切正確且總和正確。 有沒有辦法在子查詢或類似的原始查詢中做到這一點?
總計3100,是上面列出的總和的一半。 如果我從上一個查詢中刪除“ DISTINCT d.id”,則每一行都會列出兩次。
雖然每個轉儲可能只有一個類別, dump_cat
每個轉儲在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程序員的普遍誤解。
乍一看,在我看來,您可能在Dump和Dump_Cat之間具有反向引用完整性約束。
(轉儲中的)交易可以分為多個類別嗎? 如果不是,那么事務表(轉儲)是否應指定每個事務屬於哪個類別,而不是指定其他方式? 即,轉儲表中應該有一個CatId,而在Cat表中應該沒有DumpId嗎?
如果事務可以在多個類別中,則您的數據結構是正確的,但是在任何聚合查詢中,不可避免地要對交易金額進行雙(或乘)計數,因為交易金額實際上是在多個類別中。
如果轉儲記錄可以屬於多個類別,則它們將影響該月該類別的所有行。
一種解決方案是還為每個轉儲記錄提取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;
您幾乎可以接受任何查詢,例如用於創建不同表的查詢,然后從中選擇一個即可。 只需給查詢一個“表名”即可。
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
那可能不是執行查詢的最有效方法,而且我可能弄錯了一些表別名,但這應該使您知道如何執行此操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.