2012-09-25 120 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子句按參數排序)。