![](/img/trans.png)
[英]Using CASE to compare DISTINCT(COUNT()) and COUNT() columns
[英]distinct count of items using case statements
我無法獲得購買了商品A和B的客戶數量。 以下是我正在使用的數據示例。
Customer No | Item
___________________
1 A
1 B
2 B
3 A
4 A
4 B
5 B
6 A
我正在嘗試計算有多少客戶購買了商品A和B。這是我到目前為止所嘗試的。 我得到以下結果項目A = 5,項目B = 3以及項目A和B = 6。
Select
count (distinct case when ItemNo = 'A' then customerNo end) as [A],
count (distinct case when ItemNo = 'B' then customerNo end) as [B],
count (distinct case when (ItemNo = 'A' or ItemNo = 'B') then customerNo end) as [AandB]
from Items
這是我想要得到的結果:
Item | Count
A 4
B 4
A and B 2
有人可以指出我正確的方向以獲得此結果。 謝謝!
我認為您的預期結果可能是A = 4
和B = 4
。
您可以嘗試使用UNION ALL
來獲取A
, B
以及A & B
金額。
SELECT ItemNo,COUNT(distinct customerNo) Count
FROM Items
GROUP BY ItemNo
UNION ALL
SELECT 'A and B',count(*)
FROM (
SELECT COUNT(DISTINCT ItemNo) cnt
FROM Items tt
WHERE ItemNo IN ('A','B')
GROUP BY [CustomerNo]
HAVING COUNT(DISTINCT ItemNo) = 2
) t1
這是另一種方法。
SQL Server有一個有用的運算符INTERSECT
,這正是您在這里需要的-兩個集合的相交(買A
人和買B
)。
我認為它比使用HAVING
過濾器進行模糊分組更具可讀性。
在性能方面,您應該在真實數據上嘗試所有變體。
樣本數據
DECLARE @T TABLE (CustomerNo int, Item varchar(50));
INSERT INTO @T (CustomerNo, Item) VALUES
(1, 'A'),
(1, 'B'),
(2, 'B'),
(3, 'A'),
(4, 'A'),
(4, 'B'),
(5, 'B'),
(6, 'A');
詢問
SELECT
Item
,COUNT(DISTINCT CustomerNo) AS CustomerCount
,0 AS SortOrder
FROM @T
GROUP BY Item
UNION ALL
SELECT
'A & B' AS Item
,COUNT(*) AS CustomerCount
,1 AS SortOrder
FROM
(
SELECT CustomerNo
FROM @T
WHERE Item = 'A'
INTERSECT
SELECT CustomerNo
FROM @T
WHERE Item = 'B'
) AS T
ORDER BY SortOrder, Item
;
查詢的第一部分通過對Item
進行簡單分組來統計客戶。 查詢的第二部分(在UNION ALL
)計算同時購買A
和B
那些客戶。
SortOrder
列只是為了適當地排序最終結果。
結果
+-------+---------------+-----------+
| Item | CustomerCount | SortOrder |
+-------+---------------+-----------+
| A | 4 | 0 |
| B | 4 | 0 |
| A & B | 2 | 1 |
+-------+---------------+-----------+
select count (distinct case when I.ItemNo = 'A' then customerNo end) as A,
count (distinct case when I.ItemNo = 'B' then customerNo end) as B,
count (distinct case when (I.ItemNo = 'A' and (select count(*) from items as I2 where I2.itemno = 'B' and I.customerNo = I2.customerNo ) > 0)
then customerNo end) as AB
from Items as I;
您不希望在最后一個COUNT中使用“ OR”條件,而是要使用“ AND”。 在這里,我使用相關子查詢來計算同一客戶(I.customerNo = I2.customerNo)訂購itemno'B'(I2.itemno ='B')的行數。 如果計數> 0,則客戶訂購了物料A和B。
相關子查詢由I.customerNo = I2.customerNo條件建立。
如果您無法在COUNT中執行子查詢,則這是一種較長的方法,也可以使用
SELECT SUM(D.A), SUM(D.B), SUM(D.AB) FROM
(
select A, B, case when U.A > 0 AND U.B > 0 THEN 1 end AS AB
from (
select count (distinct case when I.ItemNo = 'A' then customerNo end) as A,
count (distinct case when I.ItemNo = 'B' then customerNo end) as B
from Items as I
group by I.customerNo
) AS U
) AS D;
這是一種方法。 我們可以先嘗試按客戶進行匯總以生成A和B計數。 然后,匯總這些計數。
WITH cte AS (
SELECT customerNo,
COUNT(CASE WHEN Item = 'A' THEN 1 END) AS a_cnt,
COUNT(CASE WHEN Item = 'B' THEN 1 END) AS b_cnt
FROM Items
GROUP BY customerNo
)
SELECT 'A' AS Item, COUNT(CASE WHEN a_cnt > 0 THEN 1 END) AS Count, 0 AS pos FROM cte
UNION ALL
SELECT 'B', COUNT(CASE WHEN b_cnt > 0 THEN 1 END), 1 FROM cte
UNION ALL
SELECT 'A and B', COUNT(CASE WHEN a_cnt > 0 AND b_cnt > 0 THEN 1 END), 2 FROM cte
ORDER BY pos;
我將通過兩個聚合級別來做到這一點:
select sum(has_a) as num_A,
sum(has_b) as num_B,
sum(has_a * has_b) as num_AB
from (select i.customer,
max(case when item_no = 'A' then 1 else 0 end) as has_A,
max(case when item_no = 'B' then 1 else 0 end) as has_B
from items
group by i.customer
) ic;
您還可以在不同的行上獲取此信息:
select has_a, has_b, count(*)
from (select i.customer,
max(case when item_no = 'A' then 1 else 0 end) as has_A,
max(case when item_no = 'B' then 1 else 0 end) as has_B
from items
group by i.customer
) ic
group by has_A, has_B;
這並不完全相同,因為這些值僅適用於產品組合。 換句話說,每個客戶只計算一次。 我喜歡的是:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.