2011-10-05 43 views
2

我有如下表:如何編寫分位數聚合函數?

CREATE TABLE #TEMP (ColA VARCHAR(MAX), ColB VARCHAR(MAX), Date date, Value int) 

INSERT INTO #TEMP VALUES('A','B','7/1/2010','11143274') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','13303527') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','17344238') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','13236525') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','10825232') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','13567253') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','10726342') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','11605647') 

INSERT INTO #TEMP VALUES('A','B','7/2/2010','13236525') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','10825232') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','13567253') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','10726342') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','11605647') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','17344238') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','17344238') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','17344238') 

SELECT * FROM #TEMP 

DROP TABLE #TEMP 

R(統計軟件),計算出最後一列的第95百分位值,我做這樣的事情:

ddply(data, c("ColA", "ColB", "Date"), summarize, Value95=quantile(Value, 0.95)) 

和輸出如下:

A B 2010-07-01 16022293 
A B 2010-07-02 17344238 

這一切正在做的是對執行GROUP BY操作,ColBDate並應用聚合函數quantile函數。到目前爲止這麼好,但我應該有辦法在SQL Server中執行此操作,因爲這是一個可以乾淨地在SQL中完成的聚合操作,並且當數據的數據量爲數百萬時,我真的希望在SQL中執行此操作統計軟件。

我的問題是我無法找到寫分位數函數本身的好方法。我嘗試過使用NTILE,但當GROUP BY下的行數小於100時,使用NTILE(100)是沒有意義的。有沒有一種好方法可以做到這一點?

UPDATE:從R一些輸出更多,如果它有助於:

> quantile(c(1,2,3,4,5,5), 0.95) 
95% 
    5 
> quantile(c(1,2,3,4,5,5), 0.0) 
0% 
1 
> quantile(c(1,2,3,4,5,5), 1.0) 
100% 
    5 
> quantile(c(1,2,3,4,5,5), 0.5) // MEDIAN 
50% 
3.5 
+0

你需要什麼公式?您的示例表格有8個不同的值。是最低的百分位0和最高的百分位100與其他6均勻分配還是計算不同? –

+1

是的。我認爲情況就是這樣。根據我的理解,實際上'R'正在做一些插值以獲得第95個百分點。我可以指給你:http://stackoverflow.com/questions/95007/explain-the-quantile-function-in-r?因爲我確信試圖解釋這一點,我自己會提出更多的問題而不是答案。如果有幫助,可以添加一些R的輸出。 – Legend

回答

1

這裏是我會怎麼做(代碼是有點亂)

CREATE TABLE #TEMP (ColA VARCHAR(MAX), ColB VARCHAR(MAX), Date date, Value int) 

INSERT INTO #TEMP VALUES('A','B','7/1/2010','11143274') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','13303527') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','17344238') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','13236525') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','10825232') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','13567253') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','10726342') 
INSERT INTO #TEMP VALUES('A','B','7/1/2010','11605647') 

INSERT INTO #TEMP VALUES('A','B','7/2/2010','13236525') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','10825232') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','13567253') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','10726342') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','11605647') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','17344238') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','17344238') 
INSERT INTO #TEMP VALUES('A','B','7/2/2010','17344238') 

INSERT INTO #TEMP VALUES('A','c','7/2/2010','1') 
INSERT INTO #TEMP VALUES('A','c','7/2/2010','2') 
INSERT INTO #TEMP VALUES('A','c','7/2/2010','3') 
INSERT INTO #TEMP VALUES('A','c','7/2/2010','4') 
INSERT INTO #TEMP VALUES('A','c','7/2/2010','5') 
INSERT INTO #TEMP VALUES('A','c','7/2/2010','5') 


declare @perc decimal(6,5) 
set @perc = 1.0 

select cola, colb,date, sum(value)/convert(decimal,count(value)) from (

select 
    row_number() OVER(partition by x.cola, x.colb, x.date order by x.value) as id, 
    x.*, 
    convert(int, y.zz) as j, 
    case when (y.zz - convert(int, y.zz)) = 0 then convert(int, y.zz) + 1 else convert(int, y.zz) end as k, 
    y.zz 
from 
#temp x join 
(
    SELECT 
     cola, 
     colb, 
     date, 
     count(*)*@perc zz 
    FROM 
     #TEMP 
    group by 
     cola, 
     colb, 
     date 
)y on x.cola = y.cola and x.colb = y.colb and x.date = y.date 

)xxx where id = j or id = k 
group by cola, colb, date 

有豪來計算(在使用的方法而言)更多的途徑。我正在使用SAS 5(R-2)方法。

2

當數據在數以百萬計的順序,我真的想這樣做在SQL比統計軟件。

您是否嘗試過R中的data.table包?請參閱this article比較ddply與data.table。