轉自http://csk83.sinaapp.com/?p=104
在實際應用中常常遇見這樣的情況,見下表,我們現在需要統計出來每年每個人的工資總和以及發放月份。
| user_name | year | month | money |
|---|---|---|---|
| 張三 | 2011 | 1 | 900 |
| 張三 | 2011 | 2 | 1200 |
| 張三 | 2011 | 5 | 1100 |
| 張三 | 2011 | 6 | 1300 |
| 李四 | 2011 | 1 | 1100 |
| 李四 | 2011 | 3 | 1200 |
即我們要得到下面表的結果
| user_name | year | monthes | total money |
|---|---|---|---|
| 張三 | 2011 | 1,2,5,6 | 4500 |
| 李四 | 2011 | 1,3 | 2300 |
首先我們想到的是有這樣的SQL語句:
SELECT user_name,year,myfunction(month) AS monthes, SUM(money) AS total_money FROM table GROUP BY user_name,year;
像count或者sum一樣吧數據表中的某個字段按照需要拼接起來,但是在PostgreSQL好像沒有直接的方法來實現(或許有筆者沒有發現,正因為沒有發現所以筆者才研究了半天得到下面的心得)。
方法一:在PostgreSQL中如果不自定義函數直接用SQL來實現
SELECT t1.user_name, t1.year, ARRAY_TO_STRING(array(SELECT t2.month FROM table t2 WHERE t2.user_name=t1.user_name AND t2.year=t1.year), ‘,’) AS monthes, SUM(t1.money) AS total_money FROM table t1 WHERE 1 GROUP BY t1.user_name, t1.year;
這里主要是用了PostgreSQL的內置數組函數array_to_string把數組拼接成字符串。
方法二:自己寫一個聚合函數csk_test來實現
結合上面array_to_sting的用法,根據聚合函數定義方法研究出用聚合函數來實現的方法:
– 1 開啟plpgsql的支持,如果沒有需要運行下面兩行SQL開啟plpgsql支持
CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler AS ‘$libdir/plpgsql’ LANGUAGE C;
CREATE TRUSTED LANGUAGE plpgsql HANDLER “plpgsql_call_handler”;
– 2 創建函數
—- 2.1 收集數據到一個數組
CREATE FUNCTION csk_test_start(a TEXT[], s TEXT) RETURNS TEXT[] AS $$
BEGIN
RETURN a || s;
END;
$$ LANGUAGE plpgsql;
—- 2.2 最后處理函數,把數組轉換成字符串輸出
CREATE FUNCTION csk_test_final(a TEXT[]) RETURNS TEXT AS $$
BEGIN
RETURN array_to_string(a, ‘,’);
END;
$$ LANGUAGE plpgsql;
– 3 創建聚集函數
CREATE AGGREGATE csk_test(
BASETYPE = TEXT,
SFUNC = csk_test_start,
STYPE = TEXT[],
FINALFUNC = csk_test_final
);
現在我們再次用本文開始的SQL就可以實現我們的要求了
SELECT user_name,year,csk_test(CAST(month to varchar)) AS monthes, SUM(money) AS total_money FROM table GROUP BY user_name,year;
需要注意的是,上面的聚集函數接收的數據類型是text,所以在用的時候month整型轉換成了varchar類型,當然也可以直接修改上面的代碼讓它們的類型一致。聚合函數在文本字段的處理上在PostgreSQL 8.4上測試通過了,至於數字類型其他類型轉換后是否能行沒有測試過。
方法二是通過聚合函數引用自定義函數來實現的,其實還可以直接調用系統函數array_append來實現:
CREATE AGGREGATE csk_test(
basetype = integer,
sfunc = array_append,
stype = integer[],
initcond = ‘{}’
);
可參考http://www.postgresql.org/docs/9.1/static/functions-array.html
