2013-08-19 60 views
2

我有一個表13 columns,其中一個的類型爲varchar(25),其餘的類型爲int(持有一年中的每個月的值)。選擇列間n和平均值

對於每一行,我想從12 columns中挑選top 6 int值並計算這些值的平均值。

我知道如何從給定的列中選擇前n個,但是如何跨越多列來完成?

回答

0

首先,理解使用TOP與聚合結合使用不會限制聚合,而是限制結果集。看看這個例子:

SELECT TOP 2 SUM(col) FROM 
(SELECT 1 AS col 
UNION 
SELECT 2 
UNION 
SELECT 3)sq 

結果仍然是「6」。其次,聚合不適用於跨列,只適用於行。您需要手動評估它們。也許最有效的方法是從該行創建一個表是這樣的:

SELECT 
    (SELECT MAX(myval) FROM (values (col1), (col2), (col3), (col4)) as all_values(myval)) 
FROM (SELECT 1 as col1, 2 as col2, 3 as col3, 4 as col4)sq 
0

如果您使用的是SQL Server 2005或更高版本,你可以unpivottable,然後rank的值,最後計算的averages的爲top 6 valuesidentifier

是這樣的:

;WITH UnPivoted AS (
    SELECT pk, MonthID, MonthNumber, MonthValue 
    FROM 
     (SELECT pk, Month1, Month2, Month3, Month4, Month5, Month6, Month7, Month8, Month9, Month10, Month11, Month12 
     FROM pvt) p 
    UNPIVOT 
     (pk FOR MonthNumber IN 
      (Month1, Month2, Month3, Month4, Month5, Month6, Month7, Month8, Month9, Month10, Month11, Month12) 
    )AS unpvt 
), 
UnPivotedRanked AS (
    SELECT pk, MonthValue, RANK() OVER(PARTITION BY pk ORDER BY MonthValue DESC) AS pkRanked 
    FROM UnPivoted 
    GROUP BY pk 
) 
SELECT pk, AVG(MonthValue) AS Top6Average 
FROM UnPivotedRanked 
WHERE pkRanked < 6 
GROUP BY pk 
+0

RANK不會打破關係,您可能想要ROW_NUMBER –

+0

不幸的是,使用SQL 2000。 –

4
select ID, 
     (
     select avg(C) 
     from (
      select top(6) C 
      from (values(C1),(C2),(C3),(C4),(C5),(C6),(C7), 
         (C8),(C9),(C10),(C11),(C12)) as T(C) 
      order by C desc 
      ) as T 
     ) as C 
from YourTable 

SQL Fiddle

對於SQL Server 2005也應該是這樣的,因爲你不能使用Table Value Constructor

select ID, 
     (
     select avg(C) 
     from (
      select top(6) C 
      from (select C1 union all 
        select C2 union all 
        select C3 union all 
        select C4 union all 
        select C5 union all 
        select C6 union all 
        select C7 union all 
        select C8 union all 
        select C9 union all 
        select C10 union all 
        select C11 union all 
        select C12) as T(C) 
      order by C desc 
      ) as T 
     ) as C 
from YourTable 

SQL Fiddle

而對於SQL Server 2000,這可以爲你工作。

select T1.ID, 
     avg(C) as C 
from (
    select ID, C1 as C from YourTable union all 
    select ID, C2 from YourTable union all 
    select ID, C3 from YourTable union all 
    select ID, C4 from YourTable union all 
    select ID, C5 from YourTable union all 
    select ID, C6 from YourTable union all 
    select ID, C7 from YourTable union all 
    select ID, C8 from YourTable union all 
    select ID, C9 from YourTable union all 
    select ID, C10 from YourTable union all 
    select ID, C11 from YourTable union all 
    select ID, C12 from YourTable 
    ) as T1 
where (
     select count(*) 
     from (
      select ID, C1 as C from YourTable union all 
      select ID, C2 from YourTable union all 
      select ID, C3 from YourTable union all 
      select ID, C4 from YourTable union all 
      select ID, C5 from YourTable union all 
      select ID, C6 from YourTable union all 
      select ID, C7 from YourTable union all 
      select ID, C8 from YourTable union all 
      select ID, C9 from YourTable union all 
      select ID, C10 from YourTable union all 
      select ID, C11 from YourTable union all 
      select ID, C12 from YourTable 
      ) as T2 
     where T1.ID = T2.ID and 
      T1.C <= T2.C 
    ) <= 6 
group by T1.ID 

SQL Fiddle

我不希望這是特別快。也許更好的選擇是將中間結果存儲在臨時表中。

create table #T 
(
    ID varchar(25), 
    C int 
) 

insert into #T 
select ID, C1 as C from YourTable union all 
select ID, C2 from YourTable union all 
select ID, C3 from YourTable union all 
select ID, C4 from YourTable union all 
select ID, C5 from YourTable union all 
select ID, C6 from YourTable union all 
select ID, C7 from YourTable union all 
select ID, C8 from YourTable union all 
select ID, C9 from YourTable union all 
select ID, C10 from YourTable union all 
select ID, C11 from YourTable union all 
select ID, C12 from YourTable 

select T1.ID, 
     avg(C) as C 
from #T as T1 
where (
     select count(*) 
     from #T as T2 
     where T1.ID = T2.ID and 
      T1.C <= T2.C 
    ) <= 6 
group by T1.ID 

drop table #T 
+0

@GaryGerson你應該能夠稍微改變這個查詢在sql server 2000中工作 - 看到這個演示 - http://sqlfiddle.com/#!6/53591/4 – Taryn

+0

@GaryGerson請始終標記您的問題正確的SQL Server版本,*特別是*如果您使用的版本是(a)將近14歲(b)4個主要版本已過時並且(c)完全不受任何類型的Microsoft支持。 –