使用case语句的项目数量不同

时间:2019-01-11 02:16:26

标签: sql sql-server

我无法获得购买了商品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

有人可以指出正确的方向吗?谢谢!

5 个答案:

答案 0 :(得分:2)

我认为您的预期结果可能是A = 4B = 4

您可以尝试使用UNION ALL来获取ABA & 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

答案 1 :(得分:2)

这是另一种实现方法。

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之后)计算同时购买了AB的那些客户。

SortOrder列只是为了适当地排序最终结果。

结果

+-------+---------------+-----------+
| Item  | CustomerCount | SortOrder |
+-------+---------------+-----------+
| A     |             4 |         0 |
| B     |             4 |         0 |
| A & B |             2 |         1 |
+-------+---------------+-----------+

答案 2 :(得分:1)

$($('.slides div')[++cur, cur%=max]).fadeIn(500);

您需要一个“ AND”,而不是在最后一个COUNT中使用“ OR”条件。在这里,我使用相关子查询来计算同一客户(I.customerNo = I2.customerNo)订购itemno'B'(I2.itemno ='B')的行数。如果计数> 0,则客户订购了商品A和B。

相关的子查询由I.customerNo = I2.customerNo条件建立。

这是一种较长的方法,即使您无法在COUNT中执行子查询,该方法也可以使用

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;

答案 3 :(得分:0)

这是一种方法。我们可以先尝试按客户进行汇总以生成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;

答案 4 :(得分:0)

我将通过两个聚合级别来做到这一点:

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;

这并不完全相同,因为这些值仅用于 产品组合。换句话说,每个客户只计算一次。我喜欢的是:

  • 很容易扩展到更多产品和组合。
  • 您可以更改子查询并使用计数而不是标志。
  • 仅对客户计数一次。