Sql server 如何将n列连接成一列?

Sql server 如何将n列连接成一列?,sql-server,Sql Server,我的目标是,如果我有: colmuns c1 | c2 | c3 | c4 | c5 | n.. row1 a | a | a | a | a | row2 b | b | b | b | b | rowN... 我想做一个将返回的查询 myCol aaaaa bbbbb nnnnn... 我知道我能做到 select t2.id, ( select * from mytable t1

我的目标是,如果我有:

colmuns      c1 | c2 | c3 | c4 | c5 | n..
row1          a |  a |  a |  a |  a | 
row2          b |  b |  b |  b |  b |
rowN...
我想做一个将返回的查询

   myCol
   aaaaa
   bbbbb
   nnnnn...
我知道我能做到

select t2.id, (
    select  *
    from mytable t1
    where t1.id= t2.id
    for xml path('')) as row
from mytable t2
它会像我所希望的那样,将整行和许多列放在一列中

现在,如何过滤掉xml标记

或者还有其他解决办法吗

编辑
列可能为null,如果不是varchar,则可以是int、varchar、date等

SELECT c1 + c2 + c3 + c4 + c5 + ...
FROM myTable
如果某些列可能包含空值,可以使用ISNULL()函数,如中所示

SELECT ISNULL(c1, '') + ISNULL(c2, 'x') + ...  -- note how you can substribute NULLs with any desired value
FROM myTable
您可以通过点击SQL Server元数据动态创建此类SELECT语句:

SELECT COLUMN_NAME, *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'myTable'
   AND DATA_TYPE IN ('char', 'varchar') -- can further filter out non desired colums
order by ORDINAL_POSITION    -- and also pick a given order
比如说

DECLARE @SqlStmt AS VARCHAR(8000)
DECLARE @Ctr AS INT
DECLARE @ColName AS VARCHAR(80)

DECLARE colCursor CURSOR 
   FOR SELECT COLUMN_NAME
   FROM INFORMATION_SCHEMA.COLUMNS
   WHERE table_name = 'myTable'
      AND DATA_TYPE IN ('char', 'varchar')
  ORDER BY  ORDINAL_POSITION
  FOR READ ONLY;

OPEN colCursor;

SET @Ctr = 0
SET @SqlStmt = 'SELECT '

FETCH NEXT FROM colCursor INTO @colName;
WHILE @@FETCH_STATUS = 0
BEGIN
    IF @Ctr > 0
    BEGIN
        SET @SqlStmt = @SqlStmt + ' + '; -- w/o the spaces if size is a pb
    END
    SET @Ctr = @Ctr + 1;
    SET @SqlStmt = @SqlStmt + @ColName;   -- w/ ISNULL if needed...

    FETCH NEXT FROM colCursor INTO @colName;
END;
CLOSE colCursor
DEALLOCATE colCursor

SET @SqlStmt = @SqlStmt + ' FROM ' + 'myTable'
-- Here to add to @SqlStmt (WHERE clause, other columns, other 
-- tables/join whatever...

PRINT @SqlStmt  -- OR EXEC() it ...

您只需使用T-SQL的字符串连接运算符“+”

SELECT c1 + c2 + c3 + c4 + c5 + ...
FROM myTable
如果某些列可能包含空值,可以使用ISNULL()函数,如中所示

SELECT ISNULL(c1, '') + ISNULL(c2, 'x') + ...  -- note how you can substribute NULLs with any desired value
FROM myTable
您可以通过点击SQL Server元数据动态创建此类SELECT语句:

SELECT COLUMN_NAME, *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'myTable'
   AND DATA_TYPE IN ('char', 'varchar') -- can further filter out non desired colums
order by ORDINAL_POSITION    -- and also pick a given order
比如说

DECLARE @SqlStmt AS VARCHAR(8000)
DECLARE @Ctr AS INT
DECLARE @ColName AS VARCHAR(80)

DECLARE colCursor CURSOR 
   FOR SELECT COLUMN_NAME
   FROM INFORMATION_SCHEMA.COLUMNS
   WHERE table_name = 'myTable'
      AND DATA_TYPE IN ('char', 'varchar')
  ORDER BY  ORDINAL_POSITION
  FOR READ ONLY;

OPEN colCursor;

SET @Ctr = 0
SET @SqlStmt = 'SELECT '

FETCH NEXT FROM colCursor INTO @colName;
WHILE @@FETCH_STATUS = 0
BEGIN
    IF @Ctr > 0
    BEGIN
        SET @SqlStmt = @SqlStmt + ' + '; -- w/o the spaces if size is a pb
    END
    SET @Ctr = @Ctr + 1;
    SET @SqlStmt = @SqlStmt + @ColName;   -- w/ ISNULL if needed...

    FETCH NEXT FROM colCursor INTO @colName;
END;
CLOSE colCursor
DEALLOCATE colCursor

SET @SqlStmt = @SqlStmt + ' FROM ' + 'myTable'
-- Here to add to @SqlStmt (WHERE clause, other columns, other 
-- tables/join whatever...

PRINT @SqlStmt  -- OR EXEC() it ...
如果所有列都已知:

SELECT c1 + c2 + c3 + c4 + c5 AS cAll
但是,如果您不知道这些列都是什么,这将不起作用

换言之,如果您想查询这个特定的表,它会工作,但是如果您想查询一个能处理不同表(不同的列名等)的通用查询,您需要修改要分析的每个表的查询。

如果列都已知:

SELECT c1 + c2 + c3 + c4 + c5 AS cAll
但是,如果您不知道这些列都是什么,这将不起作用

换言之,如果您想查询这个特定的表,它会工作,但是如果您想查询一个能处理不同表(不同的列名等)的通用查询,您需要修改要分析的每个表的查询。

尝试:

;with XmlValues  as
(
    select t2.id, (
        select  *
        from mytable  t1
        where t1.id= t2.id
        for xml path(''), TYPE) as row
    from mytable  t2
)
select x.row.value('.', 'VARCHAR(8000)') as readable
    FROM XmlValues AS x
编辑工作样本:

DECLARE @YourTable table (c1 int, c2 int, c3 varchar(5), c4 datetime)
INSERT INTO @YourTable VALUES (1,2,'abcde','1/1/2009')
INSERT INTO @YourTable VALUES (100,200,'zzz','12/31/2009 23:59:59')

    select t2.c1, (
        select  *
        from @YourTable  t1
        where t1.c1= t2.c1
        for xml path(''), TYPE) as row
    from @YourTable  t2

;with XmlValues  as
(
    select t2.c1, (
        select  *
        from @YourTable  t1
        where t1.c1= t2.c1
        for xml path(''), TYPE) as row
    from @YourTable  t2
)
select x.c1,x.row.value('.', 'VARCHAR(8000)') as readable
    FROM XmlValues AS x
输出:

c1          row
----------- --------------------------------------------------------------------
1           <c1>1</c1><c2>2</c2><c3>abcde</c3><c4>2009-01-01T00:00:00</c4>
100         <c1>100</c1><c2>200</c2><c3>zzz</c3><c4>2009-12-31T23:59:59</c4>

(2 row(s) affected)

c1          readable
----------- ----------------------------------
1           12abcde2009-01-01T00:00:00
100         100200zzz2009-12-31T23:59:59

(2 row(s) affected)
SELECT COALESCE(CONVERT(varchar(max),c1),'NULL')+ COALESCE(CONVERT(varchar(max),c2),'NULL')+ COALESCE(CONVERT(varchar(max),c3),'NULL')+ COALESCE(CONVERT(char(23),c4,121),'NULL') FROM YourTable
c1          c2          c3    c4
----------- ----------- ----- -----------------------
1           2           abcde 2009-01-01 00:00:00.000
100         200         zzz   2009-12-31 23:59:59.000

(2 row(s) affected)


------------------------------------------
12abcde2009-01-01 00:00:00.000
100200zzz2009-12-31 23:59:59.000

(2 row(s) affected)
输出:

c1          row
----------- --------------------------------------------------------------------
1           <c1>1</c1><c2>2</c2><c3>abcde</c3><c4>2009-01-01T00:00:00</c4>
100         <c1>100</c1><c2>200</c2><c3>zzz</c3><c4>2009-12-31T23:59:59</c4>

(2 row(s) affected)

c1          readable
----------- ----------------------------------
1           12abcde2009-01-01T00:00:00
100         100200zzz2009-12-31T23:59:59

(2 row(s) affected)
SELECT COALESCE(CONVERT(varchar(max),c1),'NULL')+ COALESCE(CONVERT(varchar(max),c2),'NULL')+ COALESCE(CONVERT(varchar(max),c3),'NULL')+ COALESCE(CONVERT(char(23),c4,121),'NULL') FROM YourTable
c1          c2          c3    c4
----------- ----------- ----- -----------------------
1           2           abcde 2009-01-01 00:00:00.000
100         200         zzz   2009-12-31 23:59:59.000

(2 row(s) affected)


------------------------------------------
12abcde2009-01-01 00:00:00.000
100200zzz2009-12-31 23:59:59.000

(2 row(s) affected)
尝试:

编辑工作样本:

DECLARE @YourTable table (c1 int, c2 int, c3 varchar(5), c4 datetime)
INSERT INTO @YourTable VALUES (1,2,'abcde','1/1/2009')
INSERT INTO @YourTable VALUES (100,200,'zzz','12/31/2009 23:59:59')

    select t2.c1, (
        select  *
        from @YourTable  t1
        where t1.c1= t2.c1
        for xml path(''), TYPE) as row
    from @YourTable  t2

;with XmlValues  as
(
    select t2.c1, (
        select  *
        from @YourTable  t1
        where t1.c1= t2.c1
        for xml path(''), TYPE) as row
    from @YourTable  t2
)
select x.c1,x.row.value('.', 'VARCHAR(8000)') as readable
    FROM XmlValues AS x
输出:

c1          row
----------- --------------------------------------------------------------------
1           <c1>1</c1><c2>2</c2><c3>abcde</c3><c4>2009-01-01T00:00:00</c4>
100         <c1>100</c1><c2>200</c2><c3>zzz</c3><c4>2009-12-31T23:59:59</c4>

(2 row(s) affected)

c1          readable
----------- ----------------------------------
1           12abcde2009-01-01T00:00:00
100         100200zzz2009-12-31T23:59:59

(2 row(s) affected)
SELECT COALESCE(CONVERT(varchar(max),c1),'NULL')+ COALESCE(CONVERT(varchar(max),c2),'NULL')+ COALESCE(CONVERT(varchar(max),c3),'NULL')+ COALESCE(CONVERT(char(23),c4,121),'NULL') FROM YourTable
c1          c2          c3    c4
----------- ----------- ----- -----------------------
1           2           abcde 2009-01-01 00:00:00.000
100         200         zzz   2009-12-31 23:59:59.000

(2 row(s) affected)


------------------------------------------
12abcde2009-01-01 00:00:00.000
100200zzz2009-12-31 23:59:59.000

(2 row(s) affected)
输出:

c1          row
----------- --------------------------------------------------------------------
1           <c1>1</c1><c2>2</c2><c3>abcde</c3><c4>2009-01-01T00:00:00</c4>
100         <c1>100</c1><c2>200</c2><c3>zzz</c3><c4>2009-12-31T23:59:59</c4>

(2 row(s) affected)

c1          readable
----------- ----------------------------------
1           12abcde2009-01-01T00:00:00
100         100200zzz2009-12-31T23:59:59

(2 row(s) affected)
SELECT COALESCE(CONVERT(varchar(max),c1),'NULL')+ COALESCE(CONVERT(varchar(max),c2),'NULL')+ COALESCE(CONVERT(varchar(max),c3),'NULL')+ COALESCE(CONVERT(char(23),c4,121),'NULL') FROM YourTable
c1          c2          c3    c4
----------- ----------- ----- -----------------------
1           2           abcde 2009-01-01 00:00:00.000
100         200         zzz   2009-12-31 23:59:59.000

(2 row(s) affected)


------------------------------------------
12abcde2009-01-01 00:00:00.000
100200zzz2009-12-31 23:59:59.000

(2 row(s) affected)

@Fredou,请参见编辑关于获取元数据以生成列列表。在这样的查询上使用游标,可以轻松地将字符串与适当的select语句链接起来,甚至可以在创建后运行语句(EXEC())之类的语句!光标循环不是必需的,如果要处理元数据表中的列,可以不进行循环,请参阅“我的最新编辑”。@KM。是的,谢谢你的提示;聪明并且很好地使用FOR XML!我不想成为诅咒者的倡导者,我自己也经常抱怨他们。。。我确实觉得
“说不就行了”
的态度有点摩尼教,因为游标和程序结构都有它们的时间和地点,当然,当应用于a)特殊性质的任务和b)计数最多为几百的结果集和c)处理更复杂需求的潜力(声明性方法必须“以案例的方式摆脱困境”时,不应引起注意您可以不使用光标进行循环。在这种情况下,请选择MAX(序号位置)从INFORMATION_SCHEMA.COLUMNS(其中TABLE_NAME是您想要的)中,您可以使用局部变量&a WHILE从1处理到最大值。在循环中选择COLUMN_NAME(其中TABLE_NAME是您想要的),ORDINAL_POSITION是当前值。我不确定INFORMATION_SCHEMA.COLUMNS上的索引,但在对您执行类似的循环时在您自己的表中,您可以确保使用索引。只需将游标循环替换为这种类型的循环,我就能够极大地提高性能。要在没有游标的情况下循环,请参见:@Fredou,请参见编辑关于获取元数据以构建列列表。在此类查询中使用游标,您可以轻松地将字符串链接到使用正确的select语句,甚至运行语句(EXEC())创建后。游标循环,只需说“不”!您的游标循环不是必需的,如果您想处理元数据表中的列,您可以自由循环,请参阅我的最新编辑。@KM。是的,谢谢您的提示;for XML的巧妙使用!我不希望成为游标的拥护者,我自己也经常抱怨它们。…我确实觉得
“只要说不”
的态度有点摩尼教,因为游标和程序结构一般都有其时间和位置,当然不应该在应用于特殊性质的任务和b)计数最多为几百的结果集和c)处理更复杂需求的潜力(声明性方法必须“以案例的方式解决问题”,您可以不使用光标循环。在这种情况下,选择MAX(序数位置)从INFORMATION_SCHEMA.COLUMNS(其中TABLE_NAME是您想要的)中,您可以使用局部变量&a WHILE从1处理到最大值。在循环中选择COLUMN_NAME(其中TABLE_NAME是您想要的),ORDINAL_POSITION是当前值。我不确定INFORMATION_SCHEMA.COLUMNS上的索引,但在对您执行类似的循环时在你自己的表中,你可以确保使用索引。通过用这种类型的循环替换游标循环,我已经能够极大地提高性能。要在没有游标的情况下循环,请看以下内容:我使用的是你的原始解决方案,因为我有大约20个联接,使用第二个联接是不可能的,谢谢我使用的是你的原始解决方案n因为我得到了大约20个连接,使用第二个连接是不可能的,谢谢