分组范围

时间:2012-09-25 13:03:47

标签: sql sql-server sql-server-2008

我有一张包含员工姓名及其供应商经历的表格。 我必须创建一个包含以下数据的表

给我的数据就像

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

请帮我查询。

4 个答案:

答案 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

更新:尝试解释。

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

主体使用cross joinexperiences表与范围连接起来。这会创建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生成标题 - 如果是1,则输出more,否则使用高范围值构造标题。第二个案例陈述使用sum(1)计数。由于聚合函数忽略空值,并且如果未找到匹配,则没有其他情况评估为null的情况,只需检查count_all是否为真(意味着经验中的这一行在此范围内计算)或vendor experience是否为{}小于或等于当前范围的上限值。在上面的例子中,第一个范围不计算11,但是将计算所有其余范围。

然后按val和count_all对结果进行分组。为了更好地了解它是如何工作的,您可以删除group by和sum()并在聚合之前查看数字。按empname排序,val将有助于查看[count]的值如何根据员工的不同val变化。

注意:我用我目前的英语水平做到了最好。如果您需要一个(或两个,或您需要的多个),请不要犹豫要求澄清。

答案 1 :(得分: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)]

答案 2 :(得分: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。

答案 3 :(得分: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子句按参数排序)。