zoukankan      html  css  js  c++  java
  • 将多行汇总为SQL Server数据的一行和一列

    问题

    我需要一种将多行汇总为一行和一列的方法。我知道我可以使用 Pivot将多行汇总为一行 ,但是我需要将所有数据串联到一行中的一列中。在本文中,我们将介绍一种简单的方法来完成此任务。

    为了说明需要什么,下面是表中的数据示例:

    每部门用户销售额

    这是我们希望最终结果看起来像的一个示例:

     
    样本输出

    如何在SQL Server中将多行汇总为单行

    将数据从多行汇总到单行对于连接数据,报告,在系统之间交换数据等等可能是必需的。这可以通过以下方式完成:

    • 本技巧文章中提出的解决方案探讨了两个SQL Server命令,这些命令可以帮助我们获得预期的结果。使用的SQL Server T-SQL命令是 STUFF和 FOR XML
    • T-SQL STUFF命令用于将结果连接在一起。在此示例中,结果用分号分隔。
    • SELECT命令的FOR XML选项具有四个选项(即RAW,AUTO,EXPLICIT或PATH)以返回结果。在此示例中,PATH参数用于以XML字符串的形式检索结果。

    请查看下面的示例,以遍历代码示例和最终解决方案,以将多行汇总到SQL Server中的单行中。

    准备样品数据

    在开始之前,我们将创建一些表和示例数据,以下脚本将为我们完成这些工作。

    CREATE TABLE SALES_SECTORS(
    SEC_ID INT,
    SEC_NAME VARCHAR(30))
    GO
    CREATE TABLE USRS(
    USR_ID INT,
    USR_NAME VARCHAR(30),
    SEC_ID INT
    )
    GO
    CREATE TABLE ADV_CAMPAIGN(
    ADV_ID INT,
    ADV_NAME VARCHAR(30)
    )
    GO
    CREATE TABLE USR_ADV_CAMPAIGN(
    USR_ID INT,
    ADV_ID INT
    )
    GO
    CREATE TABLE SEC_ADV_CAMPAIGN(
    SEC_ID INT,
    ADV_ID INT
    )
    GO
    INSERT INTO SALES_SECTORS( SEC_ID, SEC_NAME ) VALUES ( 1, 'ENTERTAINMENT' )
    INSERT INTO SALES_SECTORS( SEC_ID, SEC_NAME ) VALUES ( 2, 'CLOTHES' )
    GO
    INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 1, 'ANDERSON', 1 )
    INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 2, 'CHARLES', 1 )
    INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 3, 'DANNY', 1 )
    INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 4, 'LUCAS', 1 )
    INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 5, 'KEITH', 2 )
    INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 6, 'STEFAN', 2 )
    INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 7, 'EDUARD', 2 )
    INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 8, 'BRAD', 2 )
    GO
    INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 1, 'SONY ENTERTAINMENT' )
    INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 2, 'BEATS SOUNDS' )
    INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 3, 'BOOSE' )
    INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 4, 'POLO RALPH LAUREN' )
    INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 5, 'LACOSTE' )
    GO
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 1, 1 )
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 1, 2 )
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 2, 2 )
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 2, 3 )
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 3, 3 )
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 4, 2 )
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 5, 4 )
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 6, 5 )
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 7, 4 )
    INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 8, 5 )
    GO
    INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 1, 1 )
    INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 1, 2 )
    INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 1, 3 )
    INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 2, 4 )
    INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 2, 5 )
    GO

    SQL Server STUFF()函数

    在转到示例之前,我们需要了解上述命令的工作原理。STUFF()函数从一个初始位置将一个字符串放入另一个字符串中。这样,我们可以插入,替换或删除一个或多个字符。

    此语法为STUFF(character_expression,开始,长度,replaceWith_expression):

    • character_expression:要操作的字符串
    • 开始:开始的初始位置
    • 长度:要操纵的字符数
    • replaceWith_expression:要使用的字符

    这是如何使用STUFF命令的示例。 

     

    对于我们的示例,我们有一个如下所示的字符串:

    ;KEITH;STEFAN;EDUARD;BRAD

    我们要删除第一个; 从列表中,所以我们最终得到以下输出:

    KEITH;STEFAN;EDUARD;BRAD

    为此,我们可以使用STUFF命令来替换第一个;在带有空字符串的字符串中。

    SELECT STUFF(';KEITH;STEFAN;EDUARD;BRAD', 1, 1, '')

    这将返回以下输出:

    KEITH;STEFAN;EDUARD;BRAD

    SQL Server SELECT语句的FOR XML子句

    FOR XML子句将以XML形式返回SQL查询的结果。FOR XML有四种模式,分别是RAW,AUTO,EXPLICIT或PATH。我们将使用PATH选项,该选项为返回的每一行生成单个元素。

    如果我们使用如下常规查询,它将返回如下所示的结果集。

     

    SELECT 
       SS.SEC_NAME, 
       US.USR_NAME
    FROM SALES_SECTORS SS
    INNER JOIN USRS US ON US.SEC_ID = SS.SEC_ID
    ORDER BY 1, 2

    Users per sector sales

    如果更进一步,我们可以使用FOR XML PATH选项以XML字符串的形式返回结果,该结果会将所有数据放入一行和一列。

    SELECT 
       SS.SEC_NAME, 
       US.USR_NAME 
    FROM SALES_SECTORS SS 
    INNER JOIN USRS US ON US.SEC_ID = SS.SEC_ID 
    ORDER BY 1, 2 
    FOR XML PATH('')

    SQL Server Example to Rolling up Multiple Rows into a Single Row

    Example 1

    SELECT 
       SS.SEC_NAME, 
       (SELECT '; ' + US.USR_NAME 
        FROM USRS US
        WHERE US.SEC_ID = SS.SEC_ID
        FOR XML PATH('')) [SECTORS/USERS]
    FROM SALES_SECTORS SS
    GROUP BY SS.SEC_ID, SS.SEC_NAME
    ORDER BY 1
     
    SELECT 
       SS.SEC_NAME,
       STUFF((SELECT '; ' + US.USR_NAME 
              FROM USRS US
              WHERE US.SEC_ID = SS.SEC_ID
              FOR XML PATH('')), 1, 1, '') [SECTORS/USERS]
    FROM SALES_SECTORS SS
    GROUP BY SS.SEC_ID, SS.SEC_NAME
    ORDER BY 1
    
    
    SELECT 
       SS.SEC_NAME,
       STUFF((SELECT '; ' + US.USR_NAME 
              FROM USRS US
              WHERE US.SEC_ID = SS.SEC_ID
              ORDER BY USR_NAME
              FOR XML PATH('')), 1, 1, '') [SECTORS/USERS]
    FROM SALES_SECTORS SS
    GROUP BY SS.SEC_ID, SS.SEC_NAME
    ORDER BY 1

    Example 2

    SELECT 
       SS.SEC_NAME + ': ' +
       STUFF((SELECT '; ' + US.USR_NAME 
              FROM USRS US
              WHERE US.SEC_ID = SS.SEC_ID
              FOR XML PATH('')), 1, 1, '') [SECTORS/USERS]
    FROM SALES_SECTORS SS
    GROUP BY SS.SEC_ID, SS.SEC_NAME
    ORDER BY 1
    Users concatenated by sale sectors

    Example 3

    SELECT 
        SS.SEC_ID, 
        SS.SEC_NAME,
        STUFF((SELECT '; ' + AC.ADV_NAME + ' (' + 
                 STUFF((SELECT ',' + US.USR_NAME
                        FROM USR_ADV_CAMPAIGN UAC
                        INNER JOIN USRS US 
                              ON US.USR_ID = UAC.USR_ID
                        WHERE UAC.ADV_ID = SAC.ADV_ID
                        FOR XML PATH('')), 1, 1, '') + ')'
               FROM ADV_CAMPAIGN AC
               INNER JOIN SEC_ADV_CAMPAIGN SAC 
                     ON SAC.ADV_ID = AC.ADV_ID AND SAC.SEC_ID = SS.SEC_ID 
               ORDER BY AC.ADV_NAME
               FOR XML PATH('')), 1, 1, '') [CAMPAIGNS/USERS PER SECTOR]
    FROM SALES_SECTORS SS
    GROUP BY 
         SS.SEC_ID, 
         SS.SEC_NAME
     
    Users/Campaigns concatenated by sale sectors

    Example Rolling Up Index Columns into One Row

    SELECT 
       SCHEMA_NAME(ss.SCHEMA_id) AS SchemaName,
       ss.name as TableName, 
       ss2.name as IndexName, 
       ss2.index_id,
       ss2.type_desc,
       STUFF((SELECT ', ' + name 
        from sys.index_columns a inner join sys.all_columns b on a.object_id = b.object_id and a.column_id = b.column_id and a.object_id = ss.object_id and a.index_id = ss2.index_id and is_included_column = 0
        order by a.key_ordinal
        FOR XML PATH('')), 1, 2, '') IndexColumns,
       STUFF((SELECT ', ' + name 
        from sys.index_columns a inner join sys.all_columns b on a.object_id = b.object_id and a.column_id = b.column_id and a.object_id = ss.object_id and a.index_id = ss2.index_id and is_included_column = 1
        FOR XML PATH('')), 1, 2, '') IncludedColumns
    FROM sys.objects SS INNER JOIN SYS.INDEXES ss2 ON ss.OBJECT_ID = ss2.OBJECT_ID 
    WHERE ss.type = 'U'
    ORDER BY 1, 2, 3
  • 相关阅读:
    Moving From Top To Bottom in Detailed Block in Oracle Forms
    Determining Current Block and Current Item in Oracle Forms
    Oracle Form Data Entry Sample
    Using User-Named Triggers in Oracle Forms
    Writing On-Error Trigger In Oracle Forms
    An Example of On-Error Trigger in Oracle Forms
    Find Current Job Openings For Oracle Forms & Reports
    Examples For PLSQL Cursors
    Populating Tabular Data Block Manually Using Cursor in Oracle Forms
    Editplus格式化代码
  • 原文地址:https://www.cnblogs.com/Javi/p/13271748.html
Copyright © 2011-2022 走看看