sqlsql-serverdynamic-sql

Dynamically selecting the column to select from the row itself in SQL


I have a SQL Server table with some data as follows. The number of P columns are fixed but there will be too many columns. There will be multiple columns in the fashion like S1, S2 etc

Id SelectedP P1 P2 P3 P4 P5
1 P2 3 8 4 15 7
2 P1 0 2 6 0 3
3 P3 1 15 2 1 11
4 P4 3 4 6 2 4

I need to write a SQL statement which can get the below result. Basically which column that needs to be selected from each row depends upon the SelectedP value in that row itself. The SelectedP contains the column to select for each row.

Id SelectedP Selected-P-Value
1 P2 8
2 P1 0
3 P3 2
4 P4 2

Thanks in advance.


Solution

  • You just need a CASE expression...

    SELECT
      id,
      SelectedP,
      CASE SelectedP
        WHEN 'P1' THEN P1
        WHEN 'P2' THEN P2
        WHEN 'P3' THEN P3
        WHEN 'P4' THEN P4
        WHEN 'P5' THEN P5
      END
        AS SelectedPValue
    FROM
      yourTable
    

    This will return NULL for anything not mentioned in the CASE expression.


    EDIT:

    An option with just a little less typing...

    SELECT
      id, SelectedP, val  
    FROM   
      yourTable AS pvt
    UNPIVOT  
    (
      val FOR P IN   
      (
        P1,
        P2,
        P3,
        P4,
        P5
      )
    )
      AS unpvt
    WHERE
      SelectedP = P
    

    NOTE: If the value of SelectedP doesn't exist in the UNPIVOT, then the row will not appear at all (unlike the CASE expression which will return a NULL)

    Demo: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=b693738aac0b594cf37410ee5cb15cf5


    EDIT 2:

    I don't know if this will perform much worse than the 2nd option, but this preserves the NULL behaviour.

    (The preferred option is still to fix your data-structure.)

    SELECT
      id, SelectedP, MAX(CASE WHEN SelectedP = P THEN val END) AS val
    FROM   
       yourTable AS pvt
    UNPIVOT  
    (
      val FOR P IN   
      (
        P1,
        P2,
        P3,
        P4,
        P5
      )
    )
      AS unpvt
    GROUP BY
      id, SelectedP
    

    Demo : https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=f3f64d2fb6e11fd24d1addbe1e50f020