Split Multiple Columns into Multiple Rows

前端 未结 3 1617
花落未央
花落未央 2021-01-04 07:26

I have a table with this structure.

UserID  | UserName  | AnswerToQuestion1 | AnswerToQuestion2 | AnswerToQuestion3
1       | John      | 1                 |         


        
3条回答
  •  执念已碎
    2021-01-04 07:53

    According to Itzik Ben-Gan in Inside Microsoft SQL Server 2008: T-SQL Querying, SQL Server goes through three steps when unpivoting a table:

    1. Generate copies
    2. Extract elements
    3. Remove rows with NULLs

    Step 1: Generate copies

    A virtual table is created that has a copy of each row in the orignal table for each column that is being unpivoted. Also, a character string of the column name is stored in a new column (call this the QuestionName column). *Note: I modified the value in one of your columns to NULL to show the full process.

    UserID  UserName  AnswerTo1 AnswerToQ2 AnswerToQ3 QuestionName
    1       John      1         0          1          AnswerToQuestion1
    1       John      1         0          1          AnswerToQuestion2
    1       John      1         0          1          AnswerToQuestion3
    2       Mary      1         NULL       1          AnswerToQuestion1
    2       Mary      1         NULL       1          AnswerToQuestion2
    2       Mary      1         NULL       1          AnswerToQuestion3
    

    Step 2: Extract elements

    Then another table is created that creates a new row for each value from the source column which corresponds to the character string value in the QuestionName column. The value is stored in a new column (call this the Response column).

    UserID  UserName  QuestionName        Response
    1       John      AnswerToQuestion1   1
    1       John      AnswerToQuestion2   0
    1       John      AnswerToQuestion3   1
    2       Mary      AnswerToQuestion1   1
    2       Mary      AnswerToQuestion2   NULL
    2       Mary      AnswerToQuestion3   1
    

    Step 3: Remove rows with NULLS

    This step filters out any rows that were created with null values in the Response column. In other words, if any of the AnswerToQuestion columns had a null value, it would not be represented as an unpivoted row.

    UserID  UserName  QuestionName        Response
    1       John      AnswerToQuestion1   1
    1       John      AnswerToQuestion2   0
    1       John      AnswerToQuestion3   1
    2       Mary      AnswerToQuestion1   1
    2       Mary      AnswerToQuestion3   1
    

    If you follow those steps, you can

    1. CROSS JOIN all rows in the table against each AnswerToQuestion column name to get row copies
    2. Populate the Response column based on the matching the source column and QuestionName
    3. Remove the NULLs to get the same results without using UNPIVOT.

    An example below:

    DECLARE @t1 TABLE (UserID INT, UserName VARCHAR(10), AnswerToQuestion1 INT, 
      AnswertoQuestion2 INT, AnswerToQuestion3 INT
    ) 
    
    INSERT @t1 SELECT 1, 'John', 1, 0, 1 UNION ALL SELECT 2, 'Mary', 1, NULL, 1 
    
    SELECT
      UserID,
      UserName,
      QuestionName,
      Response
    FROM (
      SELECT
        UserID,
        UserName,
        QuestionName,
        CASE QuestionName
          WHEN 'AnswerToQuestion1' THEN AnswerToQuestion1
          WHEN 'AnswerToQuestion2' THEN AnswertoQuestion2
          ELSE AnswerToQuestion3 
        END AS Response 
      FROM @t1 t1
          CROSS JOIN (
            SELECT 'AnswerToQuestion1' AS QuestionName
            UNION ALL SELECT 'AnswerToQuestion2'
            UNION ALL SELECT 'AnswerToQuestion3'
          ) t2
        ) t3
    WHERE Response IS NOT NULL
    

提交回复
热议问题