Concat SQL中的所有列值
如何将来自sql查询返回的不同行的所有列值连接成一个值? 这是一个例子:
一个查询返回:
FOO ------ RES1 RES2 RES3
现在我想要得到如下结果:
FOOCONCAT ----- RES1RES2RES3
有没有办法在SQL中做到这一点?
在SQL Server
:
SELECT col1 AS [text()] FROM foo FOR XML PATH ('')
在MySQL
:
SELECT GROUP_CONCAT(col1 SEPARATOR '') FROM foo
在PostgreSQL
:
SELECT array_to_string ( ARRAY ( SELECT col1 FROM foo ), '' )
在Oracle
:
SELECT * FROM ( SELECT col1, ROW_NUMBER() OVER(ORDER BY 1) AS rn FROM foo MODEL DIMENSION BY (rn) MEASURES (col1, col1 AS group_concat, 0 AS mark) RULES UPDATE ( group_concat[rn > 1] = group_concat[CV() - 1] || col1[CV()], mark[ANY] = PRESENTV(mark[CV() + 1], 0, 1) ) ) WHERE mark = 1
Quassnoi的Oracle解决scheme相当出色,但我发现使用SYS_CONNECT_BY_PATH()而不是MODEL魔术更简单 。
SELECT REPLACE(MAX(SYS_CONNECT_BY_PATH(foo, '/')), '/', '') conc FROM ( SELECT T_FOO.*, ROW_NUMBER() OVER (ORDER BY FOO) R FROM T_FOO ) START WITH r=1 CONNECT BY PRIOR r = r-1;
假设它是一列有多个值,这种方法适用于MS SQL Server(我不能说其他系统)。
declare @result varchar(max) set @result = '' select @result = @result + RES from (query goes here)
mysql的方式:
select group_concat(somecolumn separator '') from sometable
这是你正在寻找的答案。 我有一种感觉,解决scheme在CONNECT BY操作中,我刚才没有使用过SYS_CONNECT_BY_PATH伪列(显示树中节点的完整path,用“/”分隔节点名称)。 假设你之前的一组“foo”值是表中的多行,按列“myKey”分组,例如:
myKey foo -------- ---------- group 1 apple group 1 orange group 1 pear group 2 ape group 2 bear group 2 kitten
您可以将数据视为树模式,并假设每个组的值代表分支上的节点。 在这种情况下,你会这样做:
SELECT myKey , SUBSTR(MAX(REPLACE(SYS_CONNECT_BY_PATH(foo, '/') ,'/' ,' ' ) ) ,2 ) FooConcat FROM ( SELECT MyKey , Foo , row_number() OVER (Partition by myKey order by myKey) NodeDepth FROM MyTable ) START WITH NodeDepth = 1 CONNECT BY PRIOR myKey = myKey AND PRIOR NodeDepth = NodeDepth -1 GROUP BY myKey ;
当然,连接值的顺序是随机的, 如果你的表有另一个列(“栏”),你可以使用作为一个上升和连续的sorting字段,你可以免去子查询(只存在一个虚拟的深度树),并直接使用表,用barreplaceNodeDepth。
编辑:自8.4.0版本以来,CUBRID提供了90%与MySQL的兼容性 。 因此,它支持与MySQL中语法相似的GROUP_CONCAT :
CREATE TABLE t(i int); INSERT INTO t VALUES (4),(2),(3),(6),(1),(5); SELECT GROUP_CONCAT(i*2+1 ORDER BY 1 SEPARATOR '') FROM t; group_concat(i*2+1 order by 1 separator '') ====================== '35791113'
相当强大,不是吗? 以下是CUBRID本地支持的替代解决scheme 。
SELECT MAX(SYS_CONNECT_BY_PATH(s_name, '')) AS conc_s_name FROM ( SELECT ROWNUM AS r, s_name FROM code ) AS res START WITH r = 1 CONNECT BY PRIOR r = r - 1;
非常有趣的是,这种连接CUBRID中的不同行列值的方式几乎和Oracle提供的@devio一样。 在CUBRID中,它看起来更容易一些。
select cast(res1 as varchar)+cast(res2 as varchar)+cast(res3 as varchar) as fooconcat from foo
如果列已经是string,则不需要投射,只需执行以下操作:
select res1 + res2 + res3 as fooconcat from foo
对于来自多行的数据,请使用PIVOT 。
连接string取决于你正在使用的数据库(你havnt提到你的问题,所以在这里去了什么版本)…
在Oracle和DB2中,您可以使用CONCAT
函数… CONCAT(string, string)
SQL Server中可以使用'+'运算符… string1 + string2 + string3
在MySQL中,它是CONCAT(string, string... n_string)
最后在PostgreSQL中是TEXTCAT(string, string)
…
…我从这个有点酷的书中得到了这个,我已经坐在O'Reilly的桌面SQL Pocket Guide上了…看看吧!
🙂
这可能不是你要找的东西,但是我过去的运气好像是这样的:
SELECT MAX(DECODE(fookey, 1, foo, NULL)) || MAX(DECODE(fookey, 2, foo, NULL)) || MAX(DECODE(fookey, 3, foo, NULL)) || MAX(DECODE(fookey, 4, foo, NULL)) , groupingvalue FROM mytable GROUP BY groupingvalue;
它是独立于平台的,当你有一个任意的,但有限的foo值时,它运行的很好,而且它们是基于其他一些关键值的。 例如,如果您有一张发票表,并且您希望从单行上的发票中看到所有行时间,并且有5个行项目的上限,则它将如下所示:
SELECT MAX(DECODE(lineno, 1, foo, NULL)) || ', ' || MAX(DECODE(lineno, 2, foo, NULL)) || ', ' || MAX(DECODE(lineno, 3, foo, NULL)) || ', ' || MAX(DECODE(lineno, 4, foo, NULL)) || ', ' || MAX(DECODE(lineno, 5, foo, NULL)) , invoiceid FROM lineitem GROUP BY invoiceid;
SQL Server 2008 R2:
declare @ColumnNameList VARCHAR(MAX) SELECT @ColumnNameList = COALESCE(@ColumnNameList +',' ,'') + ColumnName FROM <<table name>> select @ColumnNameList
从[Table]中select([col1] +','+ [col2] +','+ [col3] +','+ [col4])作为[MyCol]