Search code examples
sql-servert-sqlsql-server-2014unpivotcross-apply

TSQL Multiple column unpivot with named rows possible?


I know there are several unpivot / cross apply discussions here but I was not able to find any discussion that covers my problem. What I've got so far is the following:

SELECT Perc, Salary
FROM (
    SELECT jobid, Salary_10 AS Perc10, Salary_25 AS Perc25, [Salary_Median] AS Median
    FROM vCalculatedView
    WHERE JobID = '1'
    GROUP BY JobID, SourceID, Salary_10, Salary_25, [Salary_Median]
) a
UNPIVOT (
    Salary FOR Perc IN (Perc10, Perc25, Median)
) AS calc1

Now, what I would like is to add several other columns, eg. one named Bonus which I also want to put in Perc10, Perc25 and Median Rows.

As an alternative, I also made a query with cross apply, but here, it seems as if you can not "force" sort the rows like you can with unpivot. In other words, I can not have a custom sort, but only a sort that is according to a number within the table, if I am correct? At least, here I do get the result like I wish to have, but the rows are in a wrong order and I do not have the rows names like Perc10 etc. which would be nice.

SELECT crossapplied.Salary,
       crossapplied.Bonus
FROM vCalculatedView v
CROSS APPLY (
    VALUES
          (Salary_10, Bonus_10)
        , (Salary_25, Bonus_25)
        , (Salary_Median, Bonus_Median)
) crossapplied (Salary, Bonus)
WHERE JobID = '1'
GROUP BY crossapplied.Salary,
         crossapplied.Bonus

Perc stands for Percentile here.

Output is intended to be something like this:

+--------------+---------+-------+
| Calculation  | Salary  | Bonus |
+--------------+---------+-------+
| Perc10       |      25 |     5 |
| Perc25       |      35 |    10 |
| Median       |      27 |     8 |
+--------------+---------+-------+

Do I miss something or did I something wrong? I'm using MSSQL 2014, output is going into SSRS. Thanks a lot for any hint in advance!

Edit for clarification: The Unpivot-Method gives the following output:

    +--------------+---------+
    | Calculation  | Salary  |
    +--------------+---------+
    | Perc10       |      25 |
    | Perc25       |      35 |
    | Median       |      27 |
    +--------------+---------+

so it lacks the column "Bonus" here.

The Cross-Apply-Method gives the following output:

+---------+-------+
| Salary  | Bonus |
+---------+-------+
|      35 |    10 |
|      25 |     5 |
|      27 |     8 |
+---------+-------+

So if you compare it to the intended output, you'll notice that the column "Calculation" is missing and the row sorting is wrong (note that the line 25 | 5 is in the second row instead of the first).

Edit 2: View's definition and sample data: The view basically just adds computed columns of the table. In the table, I've got Columns like Salary and Bonus for each JobID. The View then just computes the percentiles like this:

Select 
    Percentile_Cont(0.1)
    within group (order by Salary)
    over (partition by jobID) as Salary_10,

    Percentile_Cont(0.25)
    within group (order by Salary)
    over (partition by jobID) as Salary_25
from Tabelle

So the output is like:

+----+-------+---------+-----------+-----------+
| ID | JobID | Salary  | Salary_10 | Salary_25 |
+----+-------+---------+-----------+-----------+
|  1 |     1 |     100 |        60 |        70 |
|  2 |     1 |     100 |        60 |        70 |
|  3 |     2 |     150 |        88 |       130 |
|  4 |     3 |      70 |        40 |        55 |
+----+-------+---------+-----------+-----------+

In the end, the view will be parameterized in a stored procedure.


Solution

  • Might this be your approach?

    After your edits I understand, that your solution with CROSS APPLY would comes back with the right data, but not in the correct output. You can add constant values to your VALUES and do the sorting in a wrapper SELECT:

    SELECT wrapped.Calculation,
           wrapped.Salary,
           wrapped.Bonus
    FROM
    (
        SELECT crossapplied.*
        FROM vCalculatedView v
        CROSS APPLY (
            VALUES
                  (1,'Perc10',Salary_10, Bonus_10)
                , (2,'Perc25',Salary_25, Bonus_25)
                , (3,'Median',Salary_Median, Bonus_Median)
        ) crossapplied (SortOrder,Calculation,Salary, Bonus)
        WHERE JobID = '1'
        GROUP BY crossapplied.SortOrder,
                 crossapplied.Calculation,
                 crossapplied.Salary,
                 crossapplied.Bonus
    ) AS wrapped
    ORDER BY wrapped.SortOrder