将count()后的结果分组为SQL Server中每个组的单行

时间:2018-05-26 13:35:00

标签: sql sql-server

我有这3个表mar_tbsel_tbcust_tb

mar_tb

mar_id   (int) PK
mar_name (nvarchar(50)) not null

sel_tb

sel_id (int) pk
mar_id  (int) (not null) FK

cust_tb

cust_id (int) pk
cust_active (bit) not null)
mar_id  (int) (not null) FK

我在每张表中都有这些数据

mar_tb

mar_id | mar_name
-----------------
 1       mar_one
 2       mar_two
 3       mar_three

sel_tb

sel_id |  mar_id
----------------------------
 1          1
 2          1

cust_tb

cust_id | cust_active | mar_id
----------------------------
 1         1             1
 2         1             1
 3         1             1
 4         1             1
 5         1             1
 6         1             1
 7         1             1
 8         1             1
 9         1             1
10         1             1
11         1             1
12         1             1
13         1             2
14         1             2
15         1             2
16         1             2

所有我需要得到这样的结果

mar_name  | cus_num | sel_num
--------------------------------
mar_one      12          2
mar_three    0           0
mar_two      4           0

我试着编写像这样的简单代码

select 
    mar_tb.mar_name,
    count(cust_tb.cust_id) as 'cus_num',
    count(sel_tb.sel_id) over (PARTITION  by mar_tb.mar_name ) as 'sel_num'
from 
    mar_tb
left join  
    cust_tb on cust_tb.mar_id = mar_tb.mar_id
left join
    sel_tb on sel_tb.mar_id = mar_tb.mar_id
group by 
    mar_tb.mar_name, sel_tb.sel_id

我得到了这个结果

mar_name  | cus_num | sel_num
--------------------------------
mar_one      12          2
mar_one      12          2
mar_three    0           0
mar_two      4           0

然后我通过使用像这样的子查询解决了这个问题

select
    mar_name, cus_num, sel_num 
from 
    (select 
         mar_tb.mar_name,
         count(cust_tb.cust_id) as 'cus_num',
         count(sel_tb.sel_id)over (PARTITION  by mar_tb.mar_name ) as 'sel_num'
     from  
         mar_tb
     left join
         cust_tb on cust_tb.mar_id = mar_tb.mar_id
     left join
         sel_tb on sel_tb.mar_id = mar_tb.mar_id
     group by 
         mar_tb.mar_name, sel_tb.sel_id) a
group by 
    mar_name, sel_num, cus_num

最后我得到了我需要的东西

mar_name  | cus_num | sel_num
--------------------------------
mar_one      12          2
mar_three    0           0
mar_two      4           0

问题是:有没有办法在不使用子查询或(不同)子句的情况下得到我需要的东西?

2 个答案:

答案 0 :(得分:0)

如果我理解正确,我会使用union allgroup by

select m.mar_name, sum(cus_num) as cus_num, sum(sel_num) as sel_num
from mar_tb m left join
     ((select c.mar_id, 1 as cus_num, 0 as sel_num
       from cust_tb c 
      ) union all
      (select s.mar_id, 0, 1
       from sel_tb s
      )
     ) cs 
     on m.mar_id = cs.mar_id
group by m.mar_name;

另一种方法使用apply或相关子查询:

select m.mar_name, c.cus_num, s.sel_num
from mar_tb m outer apply
     (select count(*) as cus_num
      from cust_tb c
      where c.mar_id = m.mar_id
     ) c outer apply
     (select count(*) as sel_num
      from sel_tb s
      where s.mar_id = m.mar_id
     ) s;

这两个都使用子查询,但它们更直接地计算您想要的值。我强烈建议您更关心使用distinct而不是使用子查询。

答案 1 :(得分:0)

如果我正确理解了您的问题,那么您可以尝试以下两种方式。

DECLARE @Mar_tb AS TABLE (mar_Id INT, mar_Name VARCHAR(100))
DECLARE @Sel_tb AS TABLE (sel_Id INT,Mar_Id INT)
DECLARE @cust_tb AS TABLE
(
cust_id int,
cust_active bit,
mar_id  int)

INSERT INTO @mar_tb (mar_id ,mar_name)
VALUES
 (1,'mar_one'),
 (2,'mar_two'),
 (3,'mar_three')

 INSERT INTO @sel_tb(

sel_id ,mar_id)
VALUES(1      ,    1),
 (2     ,     1),
  (3     ,     2)

 INSERT INTO @cust_tb
(cust_id , cust_active , mar_id)
VALUES
( 1      ,   1        ,    1),
( 2      ,   1        ,    1),
( 3      ,   1        ,    1),
( 4      ,   1        ,    1),
( 5      ,   1        ,    1),
( 6      ,   1        ,    1),
( 7      ,   1        ,    1),
( 8      ,   1        ,    1),
( 9      ,   1        ,    1),
(10      ,   1        ,    1),
(11      ,   1        ,    1),
(12      ,   1        ,    1),
(13      ,   1        ,    2),
(14      ,   1        ,    2),
(15      ,   1        ,    2),
(16      ,   1        ,    2)
/*

mar_name  | cus_num | sel_num
--------------------------------
mar_one      12          2
mar_three    0           0
mar_two      4           0 */


/************** Approach 1****/
SELECT m.mar_name,COUNT(DISTINCT s.sel_id) as sal, Count(DISTINCT c.cust_id) as customer
FROM @mar_tb m
LEFT OUTER JOIN @sel_tb s ON s.mar_id = m.mar_id
LEFT OUTER JOIN @cust_tb c ON c.mar_id = m.mar_id
GROUP BY m.mar_name

/************** Approach 2****/
SELECT m.mar_Name,COUNT(c.cust_Id) AS CustCount, tmp.saleCount
FROM @mar_tb m
LEFT OUTER JOIN @cust_tb c ON c.mar_id = m.mar_id
CROSS APPLY (SELECT  COUNT(1) As saleCount
             FROM @Sel_tb s
             WHERE s.Mar_Id  = m.mar_Id )tmp

GROUP BY m.mar_name,tmp.saleCount