PostgreSQL 实现列转行问题
1测试表数据
SELECT relative_label_content FROM frk_s.label_cor_gene relative_label_content ------ AA BB CC
2列转行写法
写法1:
string_agg
SELECT frwybs, string_agg(relative_label_content,',')asrelative_label_content FROM frk_s.label_cor_gene GROUPBY frwybs relative_label_content ------------ AA,BB,CC
写法2:
array_to_string(ARRAY_AGG(text),',')
SELECT frwybs, array_to_string( ARRAY_AGG(DISTINCTrelative_label_content), ',' )aslabels_content FROM frk_s.label_cor_gene GROUPBY frwybs labels_content ------------ AA,BB,CC
补充:PostgreSQL行列转换(兼容oraclepivotunpivot)
oracle11g开始内置了数据透视表pivottable这一功能,可以用来实现行列转换的功能,但是在数据量较大的时候使用性能就会较差。
pivot语法为:
SELECT... FROM... PIVOT[XML] (pivot_clause pivot_for_clause pivot_in_clause) WHERE...
oraclepivot使用例子:
–创建测试表并插入数据
createtableusr (namevarchar2(20), scoreint, classvarchar2(20) ); insertintousrvalues('a',20,'math'); insertintousrvalues('a',22,'phy'); insertintousrvalues('b',23,'phy'); insertintousrvalues('b',21,'math'); insertintousrvalues('c',22,'phy'); insertintousrvalues('c',24,'math'); insertintousrvalues('d',25,'math'); insertintousrvalues('d',23,'phy');
–使用pivot进行行列转换
SQL>select*fromusr 2pivot( sum(score) forclassin('math','phy') 345); NAME'math''phy' ---------------------------------------- d2523 a2022 b2123 c2422
我们还可以使用unpivot来实现列转行。
unpivot语法为:
SELECT... FROM... UNPIVOT[INCLUDE|EXCLUDENULLS] (unpivot_clause unpivot_for_clause unpivot_in_clause) WHERE...
oracleunpivot使用例子:
–创建测试表并插入数据
CREATETABLEt1 ( VendorIDint, Emp1int, Emp2int, Emp3int, Emp4int, Emp5int ); INSERTINTOt1VALUES(1,4,3,5,4,4); INSERTINTOt1VALUES(2,4,1,5,5,5); INSERTINTOt1VALUES(3,4,3,5,4,4); INSERTINTOt1VALUES(4,4,2,5,5,4); INSERTINTOt1VALUES(5,5,1,5,5,5);
–使用unpivot进行列转行
SQL>select*fromt1 2UNPIVOT( ordersforEmployeein(emp1,emp2,emp3,emp4,emp5) );34 VENDORIDEMPLORDERS ------------------------ 1EMP14 1EMP23 1EMP35 1EMP44 1EMP54 2EMP14 2EMP21 2EMP35 2EMP45 2EMP55 3EMP14 VENDORIDEMPLORDERS ------------------------ 3EMP23 3EMP35 3EMP44 3EMP54 4EMP14 4EMP22 4EMP35 4EMP45 4EMP54 5EMP15 5EMP21 VENDORIDEMPLORDERS ------------------------ 5EMP35 5EMP45 5EMP55 25rowsselected.
那么在pg中该如何实现oracle的pivot/unpivot的行列转行功能呢?pg中自带的tablefunc插件可以实现,我们可以使用该插件中的crosstab函数接口进行行列转换。
pg行转列例子:
–建表插入测试数据
createtabletbl(sellertext,se_yearint,se_monthint,se_amountint); insertintotblvalues('test1',2020,01,123456); insertintotblvalues('test1',2020,02,234567); insertintotblvalues('test1',2020,03,345678); insertintotblvalues('test1',2020,04,345678); insertintotblvalues('test1',2020,05,567890); insertintotblvalues('test2',2020,01,12); insertintotblvalues('test2',2020,02,23); insertintotblvalues('test2',2020,03,34); insertintotblvalues('test2',2020,04,45); insertintotblvalues('test2',2020,05,56); insertintotblvalues('test3',2020,03,12); insertintotblvalues('test3',2020,04,45); insertintotblvalues('test3',2020,05,56); insertintotblvalues('test4',2020,02,20); insertintotblvalues('test4',2020,03,30); insertintotblvalues('test4',2020,04,40); insertintotblvalues('test4',2020,05,50); insertintotblvalues('test1',2019,01,123456); insertintotblvalues('test1',2019,02,234567); insertintotblvalues('test1',2019,03,345678); insertintotblvalues('test1',2019,04,345678); insertintotblvalues('test1',2019,05,567890); insertintotblvalues('test1',2019,06,123456); insertintotblvalues('test1',2019,07,234567); insertintotblvalues('test1',2019,08,345678); insertintotblvalues('test1',2019,09,345678); insertintotblvalues('test1',2019,10,567890); insertintotblvalues('test1',2019,11,123456); insertintotblvalues('test1',2019,12,234567); insertintotblvalues('test2',2019,11,12); insertintotblvalues('test2',2019,12,23); insertintotblselect*fromtbl;
–行转列
bill=#select bill-#js->>'seller'asseller, bill-#js->>'se_year'asse_year, bill-#jan, bill-#feb, bill-#mar, bill-#apr, bill-#may, bill-#jun, bill-#jul, bill-#aug, bill-#sep, bill-#oct, bill-#nov, bill-#dec bill-#fromcrosstab( bill(#--这个是需要进行行列变换的源SQL,数据源。 bill(#--排序字段为groupby字段,最后一个字段为转换后的内容字段,导数第二个字段为行列变换的字段(内容为枚举,比如月份) bill(#--(必须在下一个参数中提取出对应的所有枚举值) bill(#$$selectjsonb_build_object('seller',seller,'se_year',se_year)asjs,se_month,sum(se_amount)fromtblgroupby1,2orderby1$$, bill(#--行列转换的行,有哪些值被提取出来作为列。这个在这里代表的是月份,也就是se_month的值 bill(#--或(select*from(values('jan'),...('dec'))t(se_month)) bill(#'selectdistinctse_monthfromtblorderby1' bill(#) bill-#as--crosstab输出格式 bill-#(jsjsonb,--第一个参数SQL内对应的orderby对应的字段(1个或多个) bill(#Jannumeric,--第一个参数SQL内对应导数第二个字段的枚举值,(行转列) bill(#febnumeric,--...同上 bill(#marnumeric, bill(#aprnumeric, bill(#maynumeric, bill(#junnumeric, bill(#julnumeric, bill(#augnumeric, bill(#sepnumeric, bill(#octnumeric, bill(#novnumeric, bill(#decnumeric bill(#) bill-#orderby1,2; seller|se_year|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec --------+---------+--------+--------+--------+--------+---------+--------+--------+--------+--------+---------+--------+-------- test1|2019|246912|469134|691356|691356|1135780|246912|469134|691356|691356|1135780|246912|469134 test1|2020|246912|469134|691356|691356|1135780||||||| test2|2019|||||||||||24|46 test2|2020|24|46|68|90|112||||||| test3|2020|||24|90|112||||||| test4|2020||40|60|80|100||||||| (6rows)
–列转行
bill=#withaas(--A对应原始数据(即需要列转行的数据) bill(#select bill(#js->>'seller'asseller, bill(#js->>'se_year'asse_year, bill(#jan, bill(#feb, bill(#mar, bill(#apr, bill(#may, bill(#jun, bill(#jul, bill(#aug, bill(#sep, bill(#oct, bill(#nov, bill(#dec bill(#fromcrosstab( bill(#--这个是需要进行行列变换的源SQL,数据源。 bill(#--排序字段为groupby字段,最后一个字段为转换后的内容字段,导数第二个字段为行列变换的字段(内容为枚举,比如月份) bill(#--(必须在下一个参数中提取出对应的所有枚举值) bill(#$$selectjsonb_build_object('seller',seller,'se_year',se_year)asjs,se_month,sum(se_amount)fromtblgroupby1,2orderby1$$, bill(#--行列转换的行,有哪些值被提取出来作为列。这个在这里代表的是月份,也就是se_month的值 bill(#--或(select*from(values('jan'),...('dec'))t(se_month)) bill(#'selectdistinctse_monthfromtblorderby1' bill(#) bill(#as--crosstab输出格式 bill(#(jsjsonb,--第一个参数SQL内对应的orderby对应的字段(1个或多个) bill(#Jannumeric,--第一个参数SQL内对应导数第二个字段的枚举值,(行转列) bill(#febnumeric,--...同上 bill(#marnumeric, bill(#aprnumeric, bill(#maynumeric, bill(#junnumeric, bill(#julnumeric, bill(#augnumeric, bill(#sepnumeric, bill(#octnumeric, bill(#novnumeric, bill(#decnumeric bill(#) bill(#orderby1,2 bill(#) bill-#, bill-#--b,用jsonb把多列合并为一列,并使用jsonb_each展开。 bill-#bas(selectseller,se_year,jsonb_each(row_to_json(a)::jsonb-'seller'::text-'se_year'::text)asrecfroma) bill-#selectseller,se_year,(b.rec).keyasmonth,(b.rec).valueassumfromb; seller|se_year|month|sum --------+---------+-------+--------- test1|2019|apr|691356 test1|2019|aug|691356 test1|2019|dec|469134 test1|2019|feb|469134 test1|2019|jan|246912 test1|2019|jul|469134 test1|2019|jun|246912 test1|2019|mar|691356 test1|2019|may|1135780 test1|2019|nov|246912 test1|2019|oct|1135780 test1|2019|sep|691356 test1|2020|apr|691356 test1|2020|aug|null test1|2020|dec|null test1|2020|feb|469134 test1|2020|jan|246912 test1|2020|jul|null test1|2020|jun|null test1|2020|mar|691356 test1|2020|may|1135780 test1|2020|nov|null test1|2020|oct|null test1|2020|sep|null test2|2019|apr|null test2|2019|aug|null test2|2019|dec|46 test2|2019|feb|null test2|2019|jan|null test2|2019|jul|null test2|2019|jun|null test2|2019|mar|null test2|2019|may|null test2|2019|nov|24 test2|2019|oct|null test2|2019|sep|null test2|2020|apr|90 test2|2020|aug|null test2|2020|dec|null test2|2020|feb|46 test2|2020|jan|24 test2|2020|jul|null test2|2020|jun|null test2|2020|mar|68 test2|2020|may|112 test2|2020|nov|null test2|2020|oct|null test2|2020|sep|null test3|2020|apr|90 test3|2020|aug|null test3|2020|dec|null test3|2020|feb|null test3|2020|jan|null test3|2020|jul|null test3|2020|jun|null test3|2020|mar|24 test3|2020|may|112 test3|2020|nov|null test3|2020|oct|null test3|2020|sep|null test4|2020|apr|80 test4|2020|aug|null test4|2020|dec|null test4|2020|feb|40 test4|2020|jan|null test4|2020|jul|null test4|2020|jun|null test4|2020|mar|60 test4|2020|may|100 test4|2020|nov|null test4|2020|oct|null test4|2020|sep|null (72rows)
以上为个人经验,希望能给大家一个参考,也希望大家多多支持毛票票。如有错误或未考虑完全的地方,望不吝赐教。