2012-09-25 207 views
0

我有一个包含员工姓名和供应商经验的表格。 我要创建一个表具有以下数据给我按范围分组

数据就像

empname vendor experience 
a  1 
b  2 
c  10 
d  11 
e  20 
f  12 
g  21 
h  22 

我要生成一个SQL查询,像这样

vendor_experience(months) count 
0-6       2 
0-12       5 
0-18       5 
more       8 

显示数据,请帮助我与查询。

+0

看看http://stackoverflow.com/questions/2483140/oracle-how-to-group-by-over-a-range - 它有点类似。 –

+0

你真的想重复计算多个范围内的人吗? –

回答

5

你可能会采用case statement获得独家范围的罪状:

select case when [vendor experience] <= 6 then '0-6' 
      when [vendor experience] <= 12 then '0-12' 
      when [vendor experience] <= 18 then '0-18' 
      else 'more' 
     end [vendor_experience(months)], 
     count (*) [count] 
    from experiences 
group by 
     case when [vendor experience] <= 6 then '0-6' 
      when [vendor experience] <= 12 then '0-12' 
      when [vendor experience] <= 18 then '0-18' 
      else 'more' 
     end 

这会产生相同的结果和你(包括的范围):

; with ranges as 
    (
    select 6 as val, 0 as count_all 
    union all 
    select 12, 0 
    union all 
    select 18, 0 
    union all 
    select 0, 1 
) 
select case when ranges.count_all = 1 
      then 'more' 
      else '0-' + convert (varchar(10), ranges.val) 
     end [vendor_experience(months)], 
     sum (case when ranges.count_all = 1 
        or experiences.[vendor experience] <= ranges.val 
       then 1 end) [count] 
    from experiences 
cross join ranges 
group by ranges.val, ranges.count_all 

count_all设置为1,以纪念开放结束范围。

Sql Fiddle is here

UPDATE:在解释的尝试。

第一部分开始with并与右括号结束称为CTE。有时它被称为inline view,因为它可以在同一查询中多次使用,并且在某些情况下是可更新的。此处用于准备范围数据,并且适当命名为ranges。这个名称在主查询中使用。 Val是范围的最大值,count_all如果范围没有上限(18+或更多,或者您希望称之为),则为1。数据行通过union all进行组合。您可以仅在括号之间复制/粘贴部分,然后运行它以查看结果。

主体加入experiences表使用cross join范围。这会创建来自experiencesranges的所有行的组合。对于d 11行会有4行,在选择列表

empname vendor experience val count_all 
d  11     6 0 
d  11     12 0 
d  11     18 0 
d  11     0 1 

第一个case语句通过检查count_all产生标题 - 如果它是一个,输出more,使用上限值else结构标题。第二种情况说明使用总和(1)进行计数。由于聚合函数忽略空值,如果未找到匹配,没有其他值的情况下计算为null,检查count_all是否为真(意味着来自经验的该行计入此范围内)就足够了,或者如果小于或等于电流范围的上限值。在上面的例子中,11不会被计入第一个范围,但会被计入所有其他范围。结果由val和count_all分组。为了更好地了解它的工作原理,您可以在汇总之前删除group by和sum()并查看数字。通过empname命令,val将帮助查看[count]的值如何根据每位员工的不同val而变化。

注意:我已经尽我所能用我目前的英语水平。如果您需要一个(或两个,或者您需要的一样多),请不要犹豫,要求澄清。

+0

删除了此评论。 –

+1

@GordonLinoff我可以,但OP要加倍计数;-) –

+0

@GordonLinoff我太仓促了,这不算双重数字。下限是不需要的,因为它是由'when'命令处理的。如果OP实际上想要重复计算,请漫步。 –

0

试试这个:

INSERT INTO ResultTable ([vendor_experience(months)], count) 
    Select *FROM 
    (
    (SELECT '0-6', Count(*) From TableA WHERE [vendor experience] <= 6 
    UNION ALL 
    SELECT '0-12', Count(*) From TableA WHERE [vendor experience] <= 12 
    UNION ALL 
    SELECT '0-18', Count(*) From TableA WHERE [vendor experience] <= 18 
    UNION ALL 
    SELECT 'more', Count(*) From TableA) as Temp 
    ) 

如果不需要重复计数,那么试试这个:

select t.[vendor_experience(months)], count(*) as count 
from (
    select case 
    when [vendor experience] between 0 and 6 then ' 0-6' 
    when [vendor experience] between 7 and 12 then '0-12' 
    when [vendor experience] between 13 and 18 then '0-18' 
    when [vendor experience] >= 19 then 'more' 
    else 'other' end as [vendor_experience(months)] 
    from TableA) t 
group by t.[vendor_experience(months)] 
+1

如果供应商体验没有编入索引,这将导致四个非常昂贵的扫描。 UNION还会导致不需要的排序操作符,并且不会与UNION ALL一起引入。 –

+0

@AaronBertrand谢谢。 –

0

更加动感一些,实现表的分组:

create table #t (name varchar(10),e int) 

insert into #t values ('a',0) 
insert into #t values ('b',4) 
insert into #t values ('c',3) 
insert into #t values ('d',13) 
insert into #t values ('e',25) 
insert into #t values ('f',4) 
insert into #t values ('g',19) 
insert into #t values ('h',15) 
insert into #t values ('i',7) 


create table #g (t int, n varchar(10)) 

insert into #g values (6, '0-6') 
insert into #g values (12, '0-12') 
insert into #g values (18, '0-18') 
insert into #g values (99999, 'more') 

select #g.n 
,COUNT(*) 
from #g 
inner join #t on #t.e <= #g.t 
group by #g.n 

例如,您可能想要使用99999的值作为例子即

0

这是一种方式来获得的累计值:

select sum(mon0_6) as mon0_6, sum(mon0_12) as mon0_12, sum(mon0_18) as mon0_18, 
     sum(more) as more 
from (select e.*, 
      (case when [vendor experience] <= 6 then 1 else 0 end) as mon0_6, 
      (case when [vendor experience] <= 12 then 1 else 0 end) as mon0_12, 
      (case when [vendor experience] <= 18 then 1 else 0 end) as mon0_18, 
      1 as more 
    ) e 

这使他们在单独的列。然后您可以使用unpivot将它们放在单独的行中。

但是,您可能会考虑在应用程序层执行累计和。我经常在Excel中做这种事情。

在SQL Server 2008中执行累计求和需要显式地或通过相关子查询进行自连接。 SQL Server 2012支持更简单的累计和语法(over子句按参数排序)。