zoukankan      html  css  js  c++  java
  • 合并多行查询数据到一行:使用自连接、FOR XML PATH('')、STUFF或REPLACE函数

    示例表 tb 数据如下

    id value
    —————
    1 aa
    1 bb
    2 aaa
    2 bbb
    2 ccc

    第一种

    SELECT id, [val]=( SELECT[value]+','FROM tb AS b WHERE b.id = a.id FOR XML PATH('') ) FROM tb AS a

    第一种显示结果 
    1 aa,bb, 
    1 aa,bb, 
    2 aaa,bbb,ccc, 
    2 aaa,bbb,ccc, 
    2 aaa,bbb,ccc,

    第二种

    SELECT id, [val]=( SELECT[value]+','FROM tb AS b WHERE b.id = a.id FOR XML PATH('') ) FROM tb AS a GROUPBY id

    第二种显示结果 
    1 aa,bb, 
    2 aaa,bbb,ccc,

    第三种 (用STUFF函数替换掉首端的逗号)

    SELECT id, [val]=STUFF( (SELECT','+[value]FROM tb AS b WHERE b.id = a.id FOR XML PATH('')) , 1 , 1 , '' ) FROM tb AS a GROUPBY id

    第三种显示结果 
    1 aa,bb 
    2 aaa,bbb,ccc

    STUFF 函数将字符串插入另一字符串。它在第一个字符串中从开始位置删除指定长度的字符;然后将第二个字符串插入第一个字符串的开始位置。
    STUFF ( character_expression , start , length ,character_expression_insert )

    第四种 (用REPLACE函数将所有空格替换成逗号)

    结果与第三种一样。


    合并分拆表数据

    --生成测试数据
    IF NOT object_id('Tab') IS NULL
    DROP TABLE Tab
    GO
    CREATE TABLE Tab( [Col1] INT ,[Col2] NVARCHAR(1))
    INSERT Tab
    SELECT 1 ,N'a' UNION ALL
    SELECT 1 ,N'b' UNION ALL
    SELECT 1 ,N'c' UNION ALL
    SELECT 2 ,N'd' UNION ALL
    SELECT 2 ,N'e' UNION ALL
    SELECT 3 ,N'f'
    GO
    
    /*----------
      1.合并表
    ----------*/
    
    --SQL2000用函数:
    GO
    IF object_id('F_Str') IS NOT NULL
    DROP FUNCTION F_Str
    GO 
    CREATE FUNCTION F_Str(@Col1 INT) 
    RETURNS NVARCHAR(100) AS 
    BEGIN 
        DECLARE @S NVARCHAR(100);
        SELECT @S=ISNULL(@S+',','')+Col2 FROM Tab WHERE Col1=@Col1
        RETURN @S
    END
    GO
    SELECT DISTINCT Col1,Col2=dbo.F_Str(Col1) FROM Tab
    GO 
    
    --SQL2005用XML:
    --方法1: (用STUFF函数替换掉首端的逗号)
    SELECT a.Col1,Col2=STUFF((SELECT ','+b.Col2 FROM Tab b WHERE b.Col1=a.Col1 FOR XML PATH('')),1,1,'')
    FROM Tab a GROUP BY a.Col1
    --方法2:
    SELECT a.Col1,Col2=STUFF(b.Col2.value('/R[1]','NVARCHAR(max)'),1,1,'') FROM (SELECT DISTINCT COl1 FROM Tab) a
    CROSS APPLY(SELECT COl2=(SELECT N','+Col2 FROM Tab WHERE Col1=a.COl1 FOR XML PATH('') , ROOT('R') , TYPE))b
    --方法3: 
    SELECT a.Col1,COl2=REPLACE(b.Col2.value('/Tab[1]','NVARCHAR(max)'),CHAR(44)+CHAR(32),CHAR(44))
    FROM (SELECT DISTINCT COl1 FROM Tab) a
    CROSS APPLY (SELECT Col2=(SELECT COl2
        FROM Tab
        WHERE COl1=a.COl1 FOR XML AUTO
          , TYPE) .query('<Tab>
                    {for $i in /Tab[position()<last()]/@COl2 return concat(string($i),",")}
                    {concat("",string(/Tab[last()]/@COl2))}
                    </Tab>') )b
    --SQL2005用CTE:   
    WITH roy AS (
        SELECT Col1,Col2,row=row_number()over(PARTITION BY COl1 ORDER BY COl1) FROM Tab
        ) ,Roy2 AS (
        SELECT COl1,CAST(COl2 AS NVARCHAR(100))COl2,row FROM Roy WHERE row=1
        UNION ALL
        SELECT a.Col1,CAST(b.COl2+','+a.COl2 AS NVARCHAR(100)),a.row FROM Roy a JOIN Roy2 b ON a.COl1=b.COl1 AND a.row=b.row+1
        )
    SELECT Col1,Col2 FROM Roy2 a WHERE row=(SELECT MAX(row) FROM roy WHERE Col1=a.COl1) ORDER BY Col1 OPTION(MAXRECURSION 0) 
    --生成结果:
    /*
    Col1        COl2
    ----------- ------------
    1           a,b,c
    2           d,e
    3           f
    
    (3 行受影响)
    */
    
    /*==========================================================================================*/
    /*----------
      2.拆分表
    ----------*/ 
    
    --生成测试数据
    IF NOT object_id('Tab') IS NULL
    DROP TABLE Tab 
    GO
    CREATE TABLE Tab( [Col1] INT ,[COl2] NVARCHAR(5))
    INSERT Tab
    SELECT 1 ,N'a,b,c' UNION ALL 
    SELECT 2 ,N'd,e' UNION ALL
    SELECT 3 ,N'f'
    GO
    
    --SQL2000用辅助表:
    IF object_id('Tempdb..#Num') IS NOT NULL 
    DROP TABLE #Num
    GO   
    SELECT TOP 100 ID=IDENTITY(INT,1,1) INTO #Num FROM syscolumns a ,syscolumns b
    SELECT a.Col1 ,COl2=SUBSTRING(a.Col2,b.ID,CHARINDEX(',',a.Col2+',',b.ID)-b.ID) FROM Tab a ,#Num b WHERE CHARINDEX(',',','+a.Col2,b.ID)=b.ID 
    --也可用 substring(','+a.COl2,b.ID,1)=',' 
    
    --SQL2005用Xml: 
    SELECT a.COl1 ,b.Col2
    FROM (SELECT Col1,COl2=CONVERT(xml,'<root><v>'+REPLACE(COl2,',','</v><v>')+'</v></root>') FROM Tab)a
    OUTER APPLY (SELECT Col2=C.v.value('.','NVARCHAR(100)') FROM a.COl2.nodes('/root/v')C(v))b
    
    --SQL2005用CTE: ;
    WITH roy AS(
    SELECT Col1,COl2=CAST(LEFT(Col2,CHARINDEX(',',Col2+',')-1) AS NVARCHAR(100)) ,Split=CAST(stuff(COl2+',',1,CHARINDEX(',',Col2+','),'') AS NVARCHAR(100)) FROM Tab
    UNION ALL
    SELECT Col1,COl2=CAST(LEFT(Split,CHARINDEX(',',Split)-1) AS NVARCHAR(100)),Split= CAST(stuff(Split,1,CHARINDEX(',',Split),'') AS NVARCHAR(100)) 
    FROM Roy
    WHERE split>''
    )
    SELECT COl1 ,COl2 FROM roy ORDER BY COl1 OPTION(MAXRECURSION 0)
    --生成结果:
    /*
    Col1        COl2
    ----------- -----
    1           a
    1           b
    1           c
    2           d
    2           e
    3           f
    */

     

  • 相关阅读:
    C++异常:exception
    C++关键字:explicit
    C++关键字:重学记录
    Unity jointmoto
    hashtable和hashmap
    Spring MVC 笔记 概述
    SQL上门2
    面试:A
    Java 初学者
    SQL上门
  • 原文地址:https://www.cnblogs.com/zhaoshujie/p/9594722.html
Copyright © 2011-2022 走看看