SQL Server中的水平DISTINCT COUNT或COUNT IF,不计算重复项

时间:2011-02-01 16:17:37

标签: sql sql-server sql-server-2005 tsql pivot

我简化了以下示例,但请知道我确实需要我描述的结果。

我有一个表格,其中包含有关客户的信息,包括他们的推荐方式。 例如MyTable(编辑:我的过度简化导致答案不起作用。他们是很好的答案,但不解决我的问题。为了清楚起见,我添加了最后一块拼图):

STORE    CUS_ID REFERRED    MONEYMADE  
 1        11        RADIO         10.00
 1        15        WALKIN        20.00
 1        11        RADIO         30.00
 2        12        RADIO         40.00
 2        12        RADIO         50.00
 3        13        WALKIN        60.00
 3        14        WALKIN        70.00

我想计算某个类型引用的 DISTINCT 客户的数量,并按商店对它们进行分组。我可以做到以下几点:

SELECT 
   STORE, COUNT(DISTINCT CUS_ID) AS COUNTEM, 
   REFERRED, SUM(MONEYMADE) 
FROM MyTable 
GROUP BY REFERRED, STORE

这给出了以下结果:

STORE    COUNTEM    REFERRED    MONEYMADE
 1        1         RADIO        40.00
 1        1         WALKIN       20.00
 2        1         RADIO        90.00
 3        2         WALKIN       130.00

但是,我真的需要这样的结果:

STORE    RADIO  RADIO_MONEY   WALKIN   WALKIN_MONEY
 1        1      40.00         1         20.00
 2        1      90.00         0         0.00
 3        0      0.00          2         130.00

我尝试使用SUM和CASE进行查询,但它会重复计算。例如:

SELECT 
   STORE, 
   SUM (CASE REFERRED WHEN 'RADIO' THEN 1 ELSE 0 END) AS RADIO,  
   SUM (CASE REFERRED WHEN 'RADIO' THEN MONEYMADE ELSE 0 END) AS RADIO_MONEY,  
   SUM (CASE REFERRED WHEN 'WALKIN' THEN 1 ELSE 0 END) AS WALKIN
   SUM (CASE REFERRED WHEN 'WALKIN' THEN MONEYMADE ELSE 0 END) AS WALKIN_MONEY, 
FROM MyTable
GROUP BY STORE

返回此错误结果:

STORE    RADIO  RADIO_MONEY   WALKIN   WALKIN_MONEY
 1        2      40.00         1         20.00
 2        2      90.00         0         0.00
 3        0      0.00          2         130.00

有没有办法解决这个问题?我搜索了“count if”类型的函数,但我发现的唯一的东西是sum-case方法。

3 个答案:

答案 0 :(得分:4)

编辑因为您需要SUM另一个字段。你应该在SUM / CASE之前做总和

使用自包含的样本数据

--TEST DATA
DECLARE @MyTable table 
(STORE int,  CUST_ID int , Referred varchar(6) ,MONEYMADE   Money )

INSERT INTO @MyTable VALUES  
(1,        11,        'RADIO' ,        10.00)
INSERT INTO @MyTable VALUES  
(1,        15,        'WALKIN',        20.00)
INSERT INTO @MyTable VALUES 
(1,        11,        'RADIO' ,       30.00)
INSERT INTO @MyTable VALUES 
(2,        12,        'RADIO' ,        40.00)
INSERT INTO @MyTable VALUES 
(2,        12,        'RADIO' ,       50.00)
INSERT INTO @MyTable VALUES 
(3,        13,        'WALKIN',        60.00)
INSERT INTO @MyTable VALUES 
(3,        14,        'WALKIN',        70.00)

- 使用PIVOT

  SELECT 
    pk.STORE,
    pk.RADIO,
    pk.WALKIN,
    ISNULL(pv.RADIO,0) as RADIO_MONEY,
    ISNULL(pv.WALKIN,0)as WALKIN_MONEY

 FROM
 (SELECT  STORE,   
          REFERRED ,
          MONEYMADE   
  FROM  @MyTable) p
          PIVOT (SUM(MONEYMADE) FOR REFERRED in (WALKIN, RADIO)) as  pv
  INNER JOIN         
 ( SELECT  DISTINCT STORE,   
                    REFERRED ,
                    CUST_ID   
   FROM  @MyTable) p
            PIVOT ( COUNT (CUST_ID) FOR REFERRED in (WALKIN, RADIO)) as  pk
  ON pv.store = pk.STORE

- 不使用PIVOT

SELECT 
   STORE,
   SUM(CASE REFERRED WHEN  'RADIO' THEN 1 ELSE 0 END )AS RADIO,
   SUM(CASE REFERRED WHEN 'WALKIN' THEN 1 ELSE 0 END )AS WALKIN,
   SUM(CASE REFERRED WHEN  'RADIO' THEN MONEYMADE ELSE 0 END )AS RADIO_MONEYMADE,
   SUM(CASE REFERRED WHEN 'WALKIN' THEN MONEYMADE ELSE 0 END )AS WALKIN_MONEYMADE
FROM   
   (

SELECT  
    STORE,   
    CUST_ID, 
    REFERRED ,
    SUM(MONEYMADE )MONEYMADE
  FROM 
    @MyTable p
  GROUP BY 
  STORE,
  REFERRED,
  CUST_ID


) t
group by store

输出两种技术

    STORE       RADIO       WALKIN      RADIO_MONEY           WALKIN_MONEY
    ----------- ----------- ----------- --------------------- ---------------------
    1           1           1           40.00                 20.00
    2           1           0           90.00                 0.00
    3           0           2           0.00                  130.00

答案 1 :(得分:0)

旋转SQL结果至少是棘手的。如果要直接从查询中显示数据,则可能必须牺牲查询灵活性并对大量信息(如列名称及其计数)进行硬编码。

所以我想建议的是在实际使用查询的后端做更多的事情。如果它是可接受的并且您可以自己旋转结果,那么您可以执行以下操作:

;with R(Referred) as (
  select distinct REFERRED from MyTable
)
select t.STORE, COUNT(*) as COUNT, t.REFERRED
from MyTable t
  left join R on r.REFERRED = t.REFERRED
group by t.STORE, t.REFERRED

答案 2 :(得分:0)

我认为,您的脚本已修改为符合您要实现的目标:

SELECT 
   STORE, 
   COUNT(DISTINCT CASE REFERRED WHEN 'RADIO' THEN CUS_ID END) AS RADIO,  
   SUM  (CASE REFERRED WHEN 'RADIO' THEN MONEYMADE ELSE 0 END) AS RADIO_MONEY,  
   COUNT(DISTINCT CASE REFERRED WHEN 'WALKIN' THEN CUS_ID END) AS WALKIN
   SUM  (CASE REFERRED WHEN 'WALKIN' THEN MONEYMADE ELSE 0 END) AS WALKIN_MONEY, 
FROM MyTable
GROUP BY STORE