복붙노트

[SQL] SQL에서 행과 열을 바꾸어하는 간단한 방법은?

SQL

SQL에서 행과 열을 바꾸어하는 간단한 방법은?

어떻게 단순히 SQL의 행과 열을 전환 할 수 있습니까? 트랜스 어떤 간단한 명령이 있습니까?

즉이 결과를 설정 :

        Paul  | John  | Tim  |  Eric
Red     1       5       1       3
Green   8       4       3       5
Blue    2       2       9       1

이 어 :

        Red  | Green | Blue
Paul    1       8       2
John    5       4       2
Tim     1       3       9
Eric    3       5       1

PIVOT이 시나리오에 대한 너무 복잡 보인다.

해결법

  1. ==============================

    1.이 데이터를 변환 할 수있는 몇 가지 방법이 있습니다. 원래의 게시물에서, 당신은 PIVOT이 시나리오가 너무 복잡한 것 같다 언급하지만,이 UNPIVOT 및 SQL Server의 PIVOT 기능을 모두 사용하여 매우 쉽게 적용 할 수 있습니다.

    이 데이터를 변환 할 수있는 몇 가지 방법이 있습니다. 원래의 게시물에서, 당신은 PIVOT이 시나리오가 너무 복잡한 것 같다 언급하지만,이 UNPIVOT 및 SQL Server의 PIVOT 기능을 모두 사용하여 매우 쉽게 적용 할 수 있습니다.

    그러나 다음 해당 UNPIVOT에 UNION ALL을 사용하여이 복제 할 수있는 기능과 PIVOT에 CASE 문으로 집계 함수에 대한 액세스 권한이없는 경우 :

    테이블 만들기 :

    CREATE TABLE yourTable([color] varchar(5), [Paul] int, [John] int, [Tim] int, [Eric] int);
    
    INSERT INTO yourTable
        ([color], [Paul], [John], [Tim], [Eric])
    VALUES
        ('Red', 1, 5, 1, 3),
        ('Green', 8, 4, 3, 5),
        ('Blue', 2, 2, 9, 1);
    

    UNION ALL, 집계 및 CASE 버전 :

    select name,
      sum(case when color = 'Red' then value else 0 end) Red,
      sum(case when color = 'Green' then value else 0 end) Green,
      sum(case when color = 'Blue' then value else 0 end) Blue
    from
    (
      select color, Paul value, 'Paul' name
      from yourTable
      union all
      select color, John value, 'John' name
      from yourTable
      union all
      select color, Tim value, 'Tim' name
      from yourTable
      union all
      select color, Eric value, 'Eric' name
      from yourTable
    ) src
    group by name
    

    데모와 SQL 바이올린을 참조하십시오

    UNION에서 ALL은 별도의 행으로 열 폴, 존, 팀, 에릭 변환하여 데이터의 UNPIVOT을 수행합니다. 그런 다음 각 색상에 대한 새로운 열을 얻을 수있는 경우 문 집계 함수의 합 ()을 적용한다.

    피벗 해제 및 피벗 정적 버전 :

    두 SQL 서버의 UNPIVOT 및 PIVOT 기능을 훨씬 더 쉽게이 변환을합니다. 정적 버전에 하드 코드 그들에게 결과를 얻기 위해 당신이 변환하고자하는 모든 값을 알고 있다면, 당신은 할 수 있습니다 :

    select name, [Red], [Green], [Blue]
    from
    (
      select color, name, value
      from yourtable
      unpivot
      (
        value for name in (Paul, John, Tim, Eric)
      ) unpiv
    ) src
    pivot
    (
      sum(value)
      for color in ([Red], [Green], [Blue])
    ) piv
    

    데모와 SQL 바이올린을 참조하십시오

    UNPIVOT와 내부 질의는 UNION ALL과 동일한 기능을 수행한다. 그것은 열 목록을 얻어 행으로 변 피봇 다음 열로 최종 변환을 수행한다.

    동적 피벗 버전 :

    당신이 열을 알 수없는 번호가있는 경우 (바울, 요한, 팀, 귀하의 예제에서 에릭)와 색상의 다음 알 수없는 번호는 UNPIVOT 다음 PIVOT에 대한 목록을 생성하는 동적 SQL을 사용하여 변환합니다 :

    DECLARE @colsUnpivot AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX),
        @colsPivot as  NVARCHAR(MAX)
    
    select @colsUnpivot = stuff((select ','+quotename(C.name)
             from sys.columns as C
             where C.object_id = object_id('yourtable') and
                   C.name <> 'color'
             for xml path('')), 1, 1, '')
    
    select @colsPivot = STUFF((SELECT  ',' 
                          + quotename(color)
                        from yourtable t
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    
    set @query 
      = 'select name, '+@colsPivot+'
          from
          (
            select color, name, value
            from yourtable
            unpivot
            (
              value for name in ('+@colsUnpivot+')
            ) unpiv
          ) src
          pivot
          (
            sum(value)
            for color in ('+@colsPivot+')
          ) piv'
    
    exec(@query)
    

    데모와 SQL 바이올린을 참조하십시오

    동적 버전은 UNPIVOT 및 PIVOT에 대한 항목의 목록을 생성하는 두 yourtable 다음 sys.columns 테이블을 쿼리합니다. 이 후 실행되는 쿼리 문자열에 추가됩니다. 동적 버전의 플러스는 색상 및 / 또는 이름의 변경 목록이있는 경우이 런타임에있는 목록을 생성 할 것이다.

    세 쿼리는 동일한 결과를 생성합니다 :

    | NAME | RED | GREEN | BLUE |
    -----------------------------
    | Eric |   3 |     5 |    1 |
    | John |   5 |     4 |    2 |
    | Paul |   1 |     8 |    2 |
    |  Tim |   1 |     3 |    9 |
    
  2. ==============================

    2.이것은 일반적으로 사전에 모든 컬럼 및 행 레이블을 알고 있어야합니다. 아래의 쿼리에서 볼 수 있듯이, 라벨은 모두 완전히 UNPIVOT과 (재) PIVOT 작업을 모두 자신의에 나열되어 있습니다.

    이것은 일반적으로 사전에 모든 컬럼 및 행 레이블을 알고 있어야합니다. 아래의 쿼리에서 볼 수 있듯이, 라벨은 모두 완전히 UNPIVOT과 (재) PIVOT 작업을 모두 자신의에 나열되어 있습니다.

    MS SQL 서버 2012 스키마 설정 :

    create table tbl (
        color varchar(10), Paul int, John int, Tim int, Eric int);
    insert tbl select 
        'Red' ,1 ,5 ,1 ,3 union all select
        'Green' ,8 ,4 ,3 ,5 union all select
        'Blue' ,2 ,2 ,9 ,1;
    

    쿼리 1 :

    select *
    from tbl
    unpivot (value for name in ([Paul],[John],[Tim],[Eric])) up
    pivot (max(value) for color in ([Red],[Green],[Blue])) p
    

    결과 :

    | NAME | RED | GREEN | BLUE |
    -----------------------------
    | Eric |   3 |     5 |    1 |
    | John |   5 |     4 |    2 |
    | Paul |   1 |     8 |    2 |
    |  Tim |   1 |     3 |    9 |
    
  3. ==============================

    3.나는 SQL에서 행과 열 전치에 몇 솔루션을 지적하고 싶습니다.

    나는 SQL에서 행과 열 전치에 몇 솔루션을 지적하고 싶습니다.

    첫 번째는 - 커서를 사용. 전문 사회의 일반적인 합의가 SQL 서버 커서 멀리에 있지만 커서의 사용이 권장된다 여전히 경우가 있습니다. 어쨌든, 커서는 행을 열로 바꾸어 다른 옵션을 우리에게 제시한다.

    열로 이조 행의 또 다른 해결책은 XML을 사용하는 것입니다.

    이조 열로 행에 XML 용액 기본적 동적 열 한계를 해결하는 것을 피봇의 최적 버전이다.

    스크립트 어드레스의 XML 버전 XML 경로의 조합을 사용하여이 제한 동적 T-SQL 일부 내장 함수 (즉 STUFF, QUOTENAME).

    이 문서에서 (일부 실제 T-SQL의 exmaples 포함)이 솔루션에 대한 좀 더 찾을 수 있습니다 : https://www.sqlshack.com/multiple-options-to-transposing-rows-into-columns/

  4. ==============================

    4.bluefeet에서이 용액에 근거 여기 전치 테이블을 생성하기 위해 동적 SQL을 사용하여 저장된 프로 시저이다. 그것은 모든 필드가 전치 열 (결과 테이블의 헤더가 될 것이다 열)을 제외한 수치입니다해야합니다 :

    bluefeet에서이 용액에 근거 여기 전치 테이블을 생성하기 위해 동적 SQL을 사용하여 저장된 프로 시저이다. 그것은 모든 필드가 전치 열 (결과 테이블의 헤더가 될 것이다 열)을 제외한 수치입니다해야합니다 :

    /****** Object:  StoredProcedure [dbo].[SQLTranspose]    Script Date: 11/10/2015 7:08:02 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author:      Paco Zarate
    -- Create date: 2015-11-10
    -- Description: SQLTranspose dynamically changes a table to show rows as headers. It needs that all the values are numeric except for the field using for     transposing.
    -- Parameters: @TableName - Table to transpose
    --             @FieldNameTranspose - Column that will be the new headers
    -- Usage: exec SQLTranspose <table>, <FieldToTranspose>
    -- =============================================
    ALTER PROCEDURE [dbo].[SQLTranspose] 
      -- Add the parameters for the stored procedure here
      @TableName NVarchar(MAX) = '', 
      @FieldNameTranspose NVarchar(MAX) = ''
    AS
    BEGIN
      -- SET NOCOUNT ON added to prevent extra result sets from
      -- interfering with SELECT statements.
      SET NOCOUNT ON;
    
      DECLARE @colsUnpivot AS NVARCHAR(MAX),
      @query  AS NVARCHAR(MAX),
      @queryPivot  AS NVARCHAR(MAX),
      @colsPivot as  NVARCHAR(MAX),
      @columnToPivot as NVARCHAR(MAX),
      @tableToPivot as NVARCHAR(MAX), 
      @colsResult as xml
    
      select @tableToPivot = @TableName;
      select @columnToPivot = @FieldNameTranspose
    
    
      select @colsUnpivot = stuff((select ','+quotename(C.name)
           from sys.columns as C
           where C.object_id = object_id(@tableToPivot) and
                 C.name <> @columnToPivot 
           for xml path('')), 1, 1, '')
    
      set @queryPivot = 'SELECT @colsResult = (SELECT  '','' 
                        + quotename('+@columnToPivot+')
                      from '+@tableToPivot+' t
                      where '+@columnToPivot+' <> ''''
              FOR XML PATH(''''), TYPE)'
    
      exec sp_executesql @queryPivot, N'@colsResult xml out', @colsResult out
    
      select @colsPivot = STUFF(@colsResult.value('.', 'NVARCHAR(MAX)'),1,1,'')
    
      set @query 
        = 'select name, rowid, '+@colsPivot+'
            from
            (
              select '+@columnToPivot+' , name, value, ROW_NUMBER() over (partition by '+@columnToPivot+' order by '+@columnToPivot+') as rowid
              from '+@tableToPivot+'
              unpivot
              (
                value for name in ('+@colsUnpivot+')
              ) unpiv
            ) src
            pivot
            (
              sum(value)
              for '+@columnToPivot+' in ('+@colsPivot+')
            ) piv
            order by rowid'
      exec(@query)
    END
    

    이 명령과 함께 제공되는 테이블을 테스트 할 수 있습니다 :

    exec SQLTranspose 'yourTable', 'color'
    
  5. ==============================

    5.내가 먼저 피벗 해제를하고 CTE에 결과를 저장하고 피벗 동작에 CTE를 사용하고 있습니다.

    내가 먼저 피벗 해제를하고 CTE에 결과를 저장하고 피벗 동작에 CTE를 사용하고 있습니다.

    데모

    with cte as
    (
    select 'Paul' as Name, color, Paul as Value 
     from yourTable
     union all
     select 'John' as Name, color, John as Value 
     from yourTable
     union all
     select 'Tim' as Name, color, Tim as Value 
     from yourTable
     union all
     select 'Eric' as Name, color, Eric as Value 
     from yourTable
     )
    
    select Name, [Red], [Green], [Blue]
    from
    (
    select *
    from cte
    ) as src
    pivot 
    (
      max(Value)
      for color IN ([Red], [Green], [Blue])
    ) as Dtpivot;
    
  6. ==============================

    6.당신이 컬럼의 여러 유형이있는 테이블 트랜스하려는 경우에만 INT 열을 이항 있도록, 다음, 라인 (39)의 끝 부분이 추가, 위의 @Paco 자라 테의 훌륭한 답변에 추가 :

    당신이 컬럼의 여러 유형이있는 테이블 트랜스하려는 경우에만 INT 열을 이항 있도록, 다음, 라인 (39)의 끝 부분이 추가, 위의 @Paco 자라 테의 훌륭한 답변에 추가 :

    and C.system_type_id = 56   --56 = type int
    

    여기에 변경되는 전체 쿼리는 다음과 같습니다

    select @colsUnpivot = stuff((select ','+quotename(C.name)
    from sys.columns as C
    where C.object_id = object_id(@tableToPivot) and
          C.name <> @columnToPivot and C.system_type_id = 56    --56 = type int
    for xml path('')), 1, 1, '')
    

    다른 system_type_id의의를 찾으려면이 실행 :

    select name, system_type_id from sys.types order by name
    
  7. ==============================

    7.난 내가 + 블루 피트의 답변에 따라 스플릿 텍스트를 트랜스을 사용하고 코드를 공유하는 것을 좋아합니다. 이 aproach에서 나는 MS SQL 2005에서 프로 시저로 구현하고있어

    난 내가 + 블루 피트의 답변에 따라 스플릿 텍스트를 트랜스을 사용하고 코드를 공유하는 것을 좋아합니다. 이 aproach에서 나는 MS SQL 2005에서 프로 시저로 구현하고있어

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author:      ELD.
    -- Create date: May, 5 2016.
    -- Description: Transpose from rows to columns the user split function.
    -- =============================================
    CREATE PROCEDURE TransposeSplit @InputToSplit VARCHAR(8000)
        ,@Delimeter VARCHAR(8000) = ','
    AS
    BEGIN
        SET NOCOUNT ON;
    
        DECLARE @colsUnpivot AS NVARCHAR(MAX)
            ,@query AS NVARCHAR(MAX)
            ,@queryPivot AS NVARCHAR(MAX)
            ,@colsPivot AS NVARCHAR(MAX)
            ,@columnToPivot AS NVARCHAR(MAX)
            ,@tableToPivot AS NVARCHAR(MAX)
            ,@colsResult AS XML
    
        SELECT @tableToPivot = '#tempSplitedTable'
    
        SELECT @columnToPivot = 'col_number'
    
        CREATE TABLE #tempSplitedTable (
            col_number INT
            ,col_value VARCHAR(8000)
            )
    
        INSERT INTO #tempSplitedTable (
            col_number
            ,col_value
            )
        SELECT ROW_NUMBER() OVER (
                ORDER BY (
                        SELECT 100
                        )
                ) AS RowNumber
            ,item
        FROM [DB].[ESCHEME].[fnSplit](@InputToSplit, @Delimeter)
    
        SELECT @colsUnpivot = STUFF((
                    SELECT ',' + quotename(C.NAME)
                    FROM [tempdb].sys.columns AS C
                    WHERE C.object_id = object_id('tempdb..' + @tableToPivot)
                        AND C.NAME <> @columnToPivot
                    FOR XML path('')
                    ), 1, 1, '')
    
        SET @queryPivot = 'SELECT @colsResult = (SELECT  '','' 
                        + quotename(' + @columnToPivot + ')
                      from ' + @tableToPivot + ' t
                      where ' + @columnToPivot + ' <> ''''
              FOR XML PATH(''''), TYPE)'
    
        EXEC sp_executesql @queryPivot
            ,N'@colsResult xml out'
            ,@colsResult OUT
    
        SELECT @colsPivot = STUFF(@colsResult.value('.', 'NVARCHAR(MAX)'), 1, 1, '')
    
        SET @query = 'select name, rowid, ' + @colsPivot + '
            from
            (
              select ' + @columnToPivot + ' , name, value, ROW_NUMBER() over (partition by ' + @columnToPivot + ' order by ' + @columnToPivot + ') as rowid
              from ' + @tableToPivot + '
              unpivot
              (
                value for name in (' + @colsUnpivot + ')
              ) unpiv
            ) src
            pivot
            (
              MAX(value)
              for ' + @columnToPivot + ' in (' + @colsPivot + ')
            ) piv
            order by rowid'
    
        EXEC (@query)
    
        DROP TABLE #tempSplitedTable
    END
    GO
    

    나는에 의해 순서없이 주문 행에 대한 방법에 대한 정보와 함께이 솔루션을 혼합하고 있습니다 (SQL Authority.com) 및 MSDN에 분할 기능 (social.msdn.microsoft.com)

    당신은 프로 시저를 실행하면

    DECLARE @RC int
    DECLARE @InputToSplit varchar(MAX)
    DECLARE @Delimeter varchar(1)
    
    set @InputToSplit = 'hello|beautiful|world'
    set @Delimeter = '|'
    
    EXECUTE @RC = [TransposeSplit] 
       @InputToSplit
      ,@Delimeter
    GO
    

    당신은 다음 결과를 obtaint

      name       rowid  1      2          3
      col_value  1      hello  beautiful  world
    
  8. ==============================

    8.이 방법은 테이블 레코드에 필드 (열) (행)에서 모든 데이터를 변환합니다.

    이 방법은 테이블 레코드에 필드 (열) (행)에서 모든 데이터를 변환합니다.

    Declare @TableName  [nvarchar](128)
    Declare @ExecStr    nvarchar(max)
    Declare @Where      nvarchar(max)
    Set @TableName = 'myTableName'
    --Enter Filtering If Exists
    Set @Where = ''
    
    --Set @ExecStr = N'Select * From '+quotename(@TableName)+@Where
    --Exec(@ExecStr)
    
    Drop Table If Exists #tmp_Col2Row
    
    Create Table #tmp_Col2Row
    (Field_Name nvarchar(128) Not Null
    ,Field_Value nvarchar(max) Null
    )
    
    Set @ExecStr = N' Insert Into #tmp_Col2Row (Field_Name , Field_Value) '
    Select @ExecStr += (Select N'Select '''+C.name+''' ,Convert(nvarchar(max),'+quotename(C.name) + ') From ' + quotename(@TableName)+@Where+Char(10)+' Union All '
             from sys.columns as C
             where (C.object_id = object_id(@TableName)) 
             for xml path(''))
    Select @ExecStr = Left(@ExecStr,Len(@ExecStr)-Len(' Union All '))
    --Print @ExecStr
    Exec (@ExecStr)
    
    Select * From #tmp_Col2Row
    Go
    
  9. ==============================

    9.나는 파코 자라 테의 솔루션을 사용할 수 있었다 그것은 아름답게 작동합니다. 나는 한 줄 ( "SET ANSI_WARNINGS ON")를 추가 할 필요가 않았다,하지만 나는 그것을 사용하거나라고하는 방식에 뭔가 독특한 할 수있다. 이 내 사용에 문제가 내가 누군가를 도와 줄 수 있기를 바랍니다 :

    나는 파코 자라 테의 솔루션을 사용할 수 있었다 그것은 아름답게 작동합니다. 나는 한 줄 ( "SET ANSI_WARNINGS ON")를 추가 할 필요가 않았다,하지만 나는 그것을 사용하거나라고하는 방식에 뭔가 독특한 할 수있다. 이 내 사용에 문제가 내가 누군가를 도와 줄 수 있기를 바랍니다 :

    이 솔루션은 실제 SQL 테이블에서 작동합니다. 나는 임시 테이블과 또한 메모리 (선언) 테이블을 시도했지만 그 작동하지 않습니다. 그래서 내 호출 코드에 내 SQL 데이터베이스에 테이블을 만든 다음 SQLTranspose를 호출합니다. 다시 말하지만, 그것은 잘 작동합니다. 그것은 내가 원하는 단지입니다. 여기에 내 문제는 다음과 같습니다

    전체 솔루션은 내가 임시로 나는 "즉시"SQLTranspose에 보내고있다 것을 준비 정보를 저장 한 다음 SQLTranspose가 호출되면 그 테이블을 삭제하는 테이블을 만들 수있는 진정한 동적 I 필요 되려면. 테이블 삭제는 나의 궁극적 인 실행 계획에 문제가 제시된다. 코드는 최종 사용자 응용 프로그램 (마이크로 소프트 Access 폼 / 메뉴 버튼)에서 실행해야합니다. 나는이 SQL 프로세스를 사용할 때 사용하는 SQL 계정이 테이블을 삭제할 수있는 권한이 없기 때문에 최종 사용자 응용 프로그램 오류 안타 (SQL 테이블을 만들 SQLTranspose, 삭제 SQL 테이블을 호출).

    나는 그림 그래서 몇 가지 해결책이 있습니다 :

    나는이 중 일부는 다른, 별도의 스레드 및 질문을 보증 할 수 있음을 인정한다. 그러나, 하나 개의 솔루션은 단순히 내가이 스레드에서 여기 내 첫 번째 게시물을 만들거야 행과 열의 이조을 할 수있는 다른 방법이 될 수있는 가능성이 있기 때문에.

    편집 : 파코가 제안 나는 또한, 끝에서 6 번째 줄에 최대 (값)과 합계 (값)를 교체했다.

    편집하다:

    나는 나를 위해 작동 뭔가를 알아 냈어. 그것이 최선의 대답인지 아닌지 모르겠어요.

    나는 strored 프로 시저를 실행하기 때문에 데이터베이스에서 출력을보고 생성하는 데 사용되는 읽기 전용 사용자 계정이 있습니다. 이후 나는 "합법적 인"테이블 (안 선언 테이블이 아닌 임시 테이블) 내가 만들 수있는 읽기 전용 사용자 계정에 대한 방법 알아 내려고했다 (그리고 나중에 삭제) 테이블과 의지 만 작품을 만든 SQLTranspose 기능 .

    나는 사용자 계정이 테이블을 생성하도록 허용하는 나의 목적 괜찮아 것을 추론했다. 사용자는 여전히하지만 테이블을 삭제할 수 없습니다. 내 솔루션은 사용자 계정 권한이있는 스키마를 만드는 것이 었습니다. 내가 사용을 만들거나 삭제할 때마다 그런 다음 해당 테이블은 지정된 스키마를 참조하십시오.

    내가 먼저 '사'또는 '시스템 관리자'계정에서이 명령을 실행 : SCHEMA RO AUTHORIZATION을 CREATE

    언제 내가 내 "tmpoutput"표를 참조 할 때 나는이 예처럼 지정

    드롭 테이블 ro.tmpoutput

  10. from https://stackoverflow.com/questions/13372276/simple-way-to-transpose-columns-and-rows-in-sql by cc-by-sa and MIT license