簡體   English   中英

在MySQL中的不同行上獲取SUM()

[英]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約束,以確保每對didcid僅存在一行:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM