有一张表,表字段如下
id varchar,
users varchar,
from_id varchar,
attach varchar,
content varchar对表中,from_id,attach,content3个字段的值,同时都相等的记录,进行合并,把他们的users字段用","相连接起来
比如举个例子:有3条记录
id users from_id attach content
1    a        b            c           d     
2    A        b            c          d
3    F         BB         ddd      dd
最后能得到:
users   from_id attach content
a,A         b           c             d
F             BB        ddd         dd
这个SQL语句应该如何写

解决方案 »

  1.   

    SQL2005下利用XML进行项目的合并与拆分
      通常情况下我们对相同项目进分组求和,那是相当的简单啦,只要select.. group by加聚合函数就行了,可是对于串一类的项目进行合并时就不这么简单了,同样分解一个按指定分隔符分隔的串或分析指定位置的串,在2000下我们通常是创建一个函数,然后分组或提取就行了,现我们主要讨论在2005下利用xml来完成这个工作。
      1、先来一个简单点,如下的例子对aaa相同的项目合并。
    ------------------------------------------------------------------------
    -- Author:  HappyFlyStone  
    -- Date  :  2009-01-04 20:57:59
    -- Ver:     Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86) 
    --       Apr 14 2006 01:12:25 
    --       Copyright (c) 1988-2005 Microsoft Corporation
    --       Standard Edition on Windows NT 5.0 (Build 2195: Service Pack 4)
    --      
    ------------------------------------------------------------------------
    -- Test Data: tb
    IF OBJECT_ID('tb') IS NOT NULL 
        DROP TABLE tb
    Go
    CREATE TABLE tb(aaa INT,bbb INT)
    Go
    INSERT INTO tb
    SELECT 1,2 UNION ALL
    SELECT 1,3 UNION ALL
    SELECT 1,4 UNION ALL
    SELECT 2,2 UNION ALL
    SELECT 2,5 
    GO
    --查询1
    select 
    aaa, 
    [values]=stuff(replace(replace((select [bbb] 
    from tb 
    where aaa=t.aaa for xml AUTO),
    '"/><tb bbb="',','),
    '"/>',''),1,9,'')
    from tb t
    group by aaa 
    --查询2
    SELECT * 
    FROM( 
        SELECT DISTINCT 
            aaa 
        FROM tb 
    )A 
    OUTER APPLY( 
        SELECT 
            [bbb]= STUFF(REPLACE(REPLACE( 
                ( 
                    SELECT [bbb] FROM tb N 
                    WHERE aaa = A.aaa 
                    FOR XML AUTO 
                ), '<N bbb="', ','), '"/>', ''), 1, 1, '') 
    )N --查询3
    select 
    aaa, 
    [values]=stuff((select ','+ltrim([bbb])
    from tb t 
    where aaa=tb.aaa for xml path('')), 1, 1, '') 
    from tb 
    group by aaa 
    drop table tb
    --查询结果
    /*
    aaa         values
    ----------- ---------
    1           2,3,4
    2           2,5(2 行受影响)*/
    2、来个两个表关联操作并实现行列转换的
    ------------------------------------------------------------------------
    -- Author:  HappyFlyStone  
    -- Date  :  2009-01-04 20:57:59
    -- Ver:     Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86) 
    --       Apr 14 2006 01:12:25 
    --       Copyright (c) 1988-2005 Microsoft Corporation
    --       Standard Edition on Windows NT 5.0 (Build 2195: Service Pack 4)
    --      
    -------------------------------------------------------------------------- Test Data: ta
    IF OBJECT_ID('ta') IS NOT NULL 
        DROP TABLE ta
    Go
    CREATE TABLE ta(pid INT,tid INT,name NVARCHAR(6))
    Go
    INSERT INTO ta
    SELECT 1,1,'hy3500' UNION ALL
    SELECT 1,2,'aabbcc' UNION ALL
    SELECT 2,3,'1111' UNION ALL
    SELECT 2,4,'2222' 
    GO
    -- Test Data: tb
    IF OBJECT_ID('tb') IS NOT NULL 
        DROP TABLE tb
    Go
    CREATE TABLE tb(NAME NVARCHAR(2),id INT)
    Go
    INSERT INTO tb
     SELECT '型号',1 UNION ALL
     SELECT '参数',2 
    GO
    --Start
    SELECT t.[name],A,B
    FROM(
    SELECT 
    B.[NAME],
    CAST((SELECT [name] FROM TA WHERE PID = A.PID FOR XML PATH('')) AS XML) AS X
    FROM TA A
    LEFT JOIN TB B ON A.PID = B.ID
    GROUP BY B.[NAME],A.PID
    ) t
    CROSS APPLY
        (SELECT A=t.x.value('/name[1]','VARCHAR(10)'),B = t.x.value('/name[2]','VARCHAR(10)')) M--Result:
    /*c    a          b
    ---- ---------- ----------
    参数   1111       2222
    型号   hy3500     aabbcc(2 行受影响)*/
    --End 3、取特定分隔符分隔的串中指定位置的串
    ------------------------------------------------------------------------
    -- Author:  HappyFlyStone  
    -- Date  :  2009-01-04 20:57:59
    -- Ver:     Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86) 
    --       Apr 14 2006 01:12:25 
    --       Copyright (c) 1988-2005 Microsoft Corporation
    --       Standard Edition on Windows NT 5.0 (Build 2195: Service Pack 4)
    --      
    ------------------------------------------------------------------------DECLARE @t TABLE(c VARCHAR(20))
    INSERT @t SELECT '双桥,9.6米,30.0吨'
    UNION ALL SELECT 'aa,bb,cc,dd'
    --通常情况如果项目在四个项目以内时,推荐一种方法:
    SELECT  REPLACE(PARSENAME(XX,3),'$$','.') C ,
        REPLACE(PARSENAME(XX,2),'$$','.') B 
    FROM
    (
        SELECT REPLACE(REPLACE(c,'.','$$'),',','.') XX FROM @T
    )AA
    --result
    /*
    c                                   b         
    --------------------------------- -----------
    双桥                                 9.6米(所影响的行数为 1 行)
    */
    好,那我们来看看2005下XML如何处理的
    SELECT A,B FROM
        (SELECT CAST('<r>' + REPLACE(c,',','</r><r>') + '</r>' AS XML) x,c FROM @t) a
    CROSS APPLY
        (SELECT A=a.x.value('/r[1]','VARCHAR(10)'),B=a.x.value('/r[2]','VARCHAR(10)')) b/*
    A          B
    ---------- ----------
    双桥         9.6米
    aa         bb(2 行受影响)
    */4、把项目串的编码用相应名称代替
    ------------------------------------------------------------------------
    -- Author:  HappyFlyStone  
    -- Date  :  2009-01-04 20:57:59
    -- Ver:     Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86) 
    --       Apr 14 2006 01:12:25 
    --       Copyright (c) 1988-2005 Microsoft Corporation
    --       Standard Edition on Windows NT 5.0 (Build 2195: Service Pack 4)
    --      
    -------------------------------------------------------------------------- Test Data: ta
    IF OBJECT_ID('ta') IS NOT NULL 
        DROP TABLE ta
    Go
    CREATE TABLE ta(ID NVARCHAR(3),number varchar(20))
    Go
    INSERT INTO ta
     SELECT '001','1,2' UNION ALL
     SELECT '002','1,2,3' 
    GO
    -- Test Data: tb
    IF OBJECT_ID('tb') IS NOT NULL 
        DROP TABLE tb
    Go
    CREATE TABLE tb(ID INT,name NVARCHAR(7))
    Go
    INSERT INTO tb
    SELECT 1,'测试一' UNION ALL
    SELECT 2,'测试二' UNION ALL
    SELECT 3,'测试三' 
    GO
    --Start
    --查询一
    SELECT C.ID,NUMBER = STUFF(REPLACE(REPLACE((
    SELECT  B.NAME  AS NAME
    FROM TA A
    LEFT JOIN 
    ( SELECT ID,NAME
      FROM TB
    ) B 
    ON CHARINDEX(','+LTRIM(B.ID)+',',','+A.NUMBER+',')>0
    WHERE A.ID = C.ID
    FOR XML AUTO
        ),'"/><B NAME="',','),'"/>',''),1,9,'')
    FROM TA C
    --查询二
    SELECT A.ID,NUMBER=STUFF(
    (SELECT ','+NAME 
     FROM TB 
     WHERE CHARINDEX(','+LTRIM(ID)+',',','+A.NUMBER+',')>0 
     FOR XML PATH(''),ROOT('R'),TYPE).value('/R[1]','NVARCHAR(MAX)')
    ,1,1,'') 
    FROM TA A--Result:
    /*id   number
    ---- -----------------
    001  测试一,测试二
    002  测试一,测试二,测试三(2 行受影响)
    */
    --End 
    5、最后我们来说说折分吧
    如:
    /*
    id          value
    ----------- -----------
    1           aa,bb
    2           aaa,bbb,ccc
    欲按id,分拆value列, 分拆后结果如下:
    id          value
    ----------- --------
    1           aa
    1           bb
    2           aaa
    2           bbb
    2           ccc
    */
    一般我们在2000下会借助中间生成一个连续的序列,然后和表关联折分,在2005下我们可借助CTE生成一个序列然后再拆分 
    CREATE TABLE TB(ID INT,VALUE VARCHAR(30))
    INSERT INTO TB VALUES(1,'AA,BB')
    INSERT INTO TB VALUES(2,'AAA,BBB,CCC')
    GO
    IF OBJECT_ID('TEMPDB..#NUM') IS NOT NULL
        DROP TABLE #NUM
    GO
    --2000
    SELECT TOP 100 ID=IDENTITY(INT,1,1) INTO #NUM FROM SYS.SYSCOLUMNS A,SYS.SYSCOLUMNS B
    SELECT 
        A.ID,[VALUE]=SUBSTRING(A.[VALUE],B.ID,CHARINDEX(',',A.[VALUE]+',',B.ID)-B.ID) 
    FROM 
        TB A,#NUM B
    WHERE
        CHARINDEX(',',','+A.[VALUE],B.ID)=B.ID --也可用 SUBSTRING(','+A.COL2,B.ID,1)=','
    --2005
    ;WITH T
    AS
    (
    SELECT 1 AS ID 
        UNION ALL
        SELECT ID + 1 FROM T WHERE ID < 100)
    SELECT 
        A.ID,[VALUE]=SUBSTRING(A.[VALUE],B.ID,CHARINDEX(',',A.[VALUE]+',',B.ID)-B.ID) 
    FROM 
        TB A,T B
    WHERE
        CHARINDEX(',',','+A.[VALUE],B.ID)=B.ID --也可用 SUBSTRING(','+A.COL2,B.ID,1)=','DROP TABLE TB,#NUM
    ------------------------------------------------------------------------
    -- Author:  HappyFlyStone  
    -- Date  :  2009-01-04 20:57:59
    -- Ver:     Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86) 
    --       Apr 14 2006 01:12:25 
    --       Copyright (c) 1988-2005 Microsoft Corporation
    --       Standard Edition on Windows NT 5.0 (Build 2195: Service Pack 4)
    --      
    ------------------------------------------------------------------------CREATE TABLE TB(ID INT,VALUE VARCHAR(30))
    INSERT INTO TB VALUES(1,'AA,BB')
    INSERT INTO TB VALUES(2,'AAA,BBB,CCC')
    GO
    SELECT A.ID, B.VALUE
    FROM(
        SELECT ID, 
    [value] = CONVERT(XML,'<ROOT><V>' + REPLACE([VALUE], ',', '</V><V>') + '</V></ROOT>') 
    FROM tb
    )A
    OUTER APPLY(
        SELECT value = N.v.value('.', 'varchar(100)') 
    FROM A.[value].nodes('/ROOT/V') N(v)
    )BDROP TABLE tb
    --查询结果
    /*
    id          value
    ----------- ------------------------------
    1           aa
    1           bb
    2           aaa
    2           bbb
    2           ccc(5 行受影响)
    */
      

  2.   

    /*
    标题:按某字段合并字符串之一(简单合并)
    作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开)
    时间:2008-11-06
    地点:广东深圳描述:将如下形式的数据按id字段合并value字段。
    id    value
    ----- ------
    1     aa
    1     bb
    2     aaa
    2     bbb
    2     ccc
    需要得到结果:
    id     value
    ------ -----------
    1      aa,bb
    2      aaa,bbb,ccc
    即:group by id, 求 value 的和(字符串相加)
    */
    --1、sql2000中只能用自定义的函数解决
    create table tb(id int, value varchar(10))
    insert into tb values(1, 'aa')
    insert into tb values(1, 'bb')
    insert into tb values(2, 'aaa')
    insert into tb values(2, 'bbb')
    insert into tb values(2, 'ccc')
    gocreate function dbo.f_str(@id varchar(10)) returns varchar(1000)
    as
    begin
      declare @str varchar(1000)
      select @str = isnull(@str + ',' , '') + cast(value as varchar) from tb where id = @id
      return @str
    end
    go--调用函数
    select id , value = dbo.f_str(id) from tb group by iddrop function dbo.f_str
    drop table tb
    --2、sql2005中的方法
    create table tb(id int, value varchar(10))
    insert into tb values(1, 'aa')
    insert into tb values(1, 'bb')
    insert into tb values(2, 'aaa')
    insert into tb values(2, 'bbb')
    insert into tb values(2, 'ccc')
    goselect id, [value] = stuff((select ',' + [value] from tb t where id = tb.id for xml path('')) , 1 , 1 , '')
    from tb
    group by iddrop table tb
    --3、使用游标合并数据
    create table tb(id int, value varchar(10))
    insert into tb values(1, 'aa')
    insert into tb values(1, 'bb')
    insert into tb values(2, 'aaa')
    insert into tb values(2, 'bbb')
    insert into tb values(2, 'ccc')
    go
    declare @t table(id int,value varchar(100))--定义结果集表变量
    --定义游标并进行合并处理
    declare my_cursor cursor local for
    select id , value from tb
    declare @id_old int , @id int , @value varchar(10) , @s varchar(100)
    open my_cursor
    fetch my_cursor into @id , @value
    select @id_old = @id , @s=''
    while @@FETCH_STATUS = 0
    begin
        if @id = @id_old
           select @s = @s + ',' + cast(@value as varchar)
        else
          begin
            insert @t values(@id_old , stuff(@s,1,1,''))
            select @s = ',' + cast(@value as varchar) , @id_old = @id
          end
        fetch my_cursor into @id , @value
    END
    insert @t values(@id_old , stuff(@s,1,1,''))
    close my_cursor
    deallocate my_cursorselect * from @t
    drop table tb
      

  3.   

    参考:http://blog.csdn.net/htl258/archive/2009/03/15/3993029.aspx
      

  4.   

    用SELECT DISTINCT .... FROM ...最快捷