我有一個表13 columns
,其中一個的類型爲varchar(25)
,其餘的類型爲int(持有一年中的每個月的值)。選擇列間n和平均值
對於每一行,我想從12 columns
中挑選top 6 int
值並計算這些值的平均值。
我知道如何從給定的列中選擇前n個,但是如何跨越多列來完成?
我有一個表13 columns
,其中一個的類型爲varchar(25)
,其餘的類型爲int(持有一年中的每個月的值)。選擇列間n和平均值
對於每一行,我想從12 columns
中挑選top 6 int
值並計算這些值的平均值。
我知道如何從給定的列中選擇前n個,但是如何跨越多列來完成?
首先,理解使用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
如果您使用的是SQL Server 2005或更高版本,你可以unpivot
的table
,然後rank
的值,最後計算的averages
的爲top 6 values
每identifier
。
是這樣的:
;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
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 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 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
我不希望這是特別快。也許更好的選擇是將中間結果存儲在臨時表中。
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
@GaryGerson你應該能夠稍微改變這個查詢在sql server 2000中工作 - 看到這個演示 - http://sqlfiddle.com/#!6/53591/4 – Taryn
@GaryGerson請始終標記您的問題正確的SQL Server版本,*特別是*如果您使用的版本是(a)將近14歲(b)4個主要版本已過時並且(c)完全不受任何類型的Microsoft支持。 –
RANK不會打破關係,您可能想要ROW_NUMBER –
不幸的是,使用SQL 2000。 –