Question

I've been trying to wrap my feeble mind around this one for some time, but I am having difficulty. I have looked at a few other examples like this SE.DBA answer, but I am having difficulty applying it to my exact situation. I do not care if the solution uses PIVOT/UNPIVOT or Cross Apply.

I am using GROUP BY because there are maybe 15-45 records per payroll, and I want all those records summed up per payroll. I am using SQLServer 2016.

The DDL and data below show the source data and the PIVOT query that I currently have

--Source data table
CREATE TABLE #EmployeeTaxes
(
     Employee int
    ,Payroll int
    ,FIT  DECIMAL(19,2)
    ,Employee_FICA DECIMAL(19,2)
    ,Employer_FICA DECIMAL(19,2)
    ,Employee_MEDI DECIMAL(19,2)
    ,Employer_MEDI DECIMAL(19,2)
    ,FIT_Gross  DECIMAL(19,2)
    ,Employee_FICA_Gross DECIMAL(19,2)
    ,Employer_FICA_Gross DECIMAL(19,2)
    ,Employee_MEDI_Gross DECIMAL(19,2)
    ,Employer_MEDI_Gross DECIMAL(19,2)
)

--Data in source table
INSERT INTO #EmployeeTaxes
VALUES (1, 1, 100.00, 150.00, 50.00, 200.00, 200.00,  20000.00, 20000.00, 20000.00, 20000.00, 20000.00)
      ,(2, 1, 100.00, 150.00, 50.00, 200.00, 200.00,  20000.00, 20000.00, 20000.00, 20000.00, 20000.00)
      ,(3, 1, 100.00, 150.00, 50.00, 200.00, 200.00,  20000.00, 20000.00, 20000.00, 20000.00, 20000.00)
      ,(1, 2, 200.00, 250.00, 150.00, 300.00, 300.00, 25000.00, 25000.00, 25000.00, 25000.00, 25000.00)
      ,(2, 2, 200.00, 250.00, 150.00, 300.00, 300.00, 25000.00, 25000.00, 25000.00, 25000.00, 25000.00)
      ,(3, 2, 200.00, 250.00, 150.00, 300.00, 300.00, 25000.00, 25000.00, 25000.00, 25000.00, 25000.00)
      ,(1, 3, 300.00, 350.00, 250.00, 400.00, 400.00, 30000.00, 30000.00, 30000.00, 30000.00, 30000.00)
      ,(2, 3, 300.00, 350.00, 250.00, 400.00, 400.00, 30000.00, 30000.00, 30000.00, 30000.00, 30000.00)
      ,(3, 3, 300.00, 350.00, 250.00, 400.00, 400.00, 30000.00, 30000.00, 30000.00, 30000.00, 30000.00)


--Basic data layout as it currently is
SELECT PAYROLL
    ,sum(fit)                       AS SumFIT
    ,sum(fit_gross)                 AS SumFIT_Gross
    ,sum(employee_fica)             AS Sum_EE_FICA
    ,sum(employee_fica_gross)       AS Sum_EE_FICA_Gross
    ,sum(employer_fica)             AS Sum_ER_FICA
    ,sum(employer_fica_gross)       AS Sum_ER_FICA_Gross
    ,sum(employee_medi)             AS Sum_EE_Medi
    ,sum(employee_medi_gross)       AS Sum_EE_Medi_Gross
    ,sum(employer_medi)             AS Sum_ER_Medi
    ,sum(employer_medi_gross)       AS Sum_ER_Medi_Gross
FROM #EmployeeTaxes
GROUP BY Payroll

--The query as I have it now, missing the Gross column
SELECT PAYROLL
      ,[Taxes]
      ,[Tax]      
FROM 
(
SELECT PAYROLL
    ,sum(fit)                       AS SumFIT
    ,sum(fit_gross)                 AS SumFIT_Gross
    ,sum(employee_fica)             AS Sum_EE_FICA
    ,sum(employee_fica_gross)       AS Sum_EE_FICA_Gross
    ,sum(employer_fica)             AS Sum_ER_FICA
    ,sum(employer_fica_gross)       AS Sum_ER_FICA_Gross
    ,sum(employee_medi)             AS Sum_EE_Medi
    ,sum(employee_medi_gross)       AS Sum_EE_Medi_Gross
    ,sum(employer_medi)             AS Sum_ER_Medi
    ,sum(employer_medi_gross)       AS Sum_ER_Medi_Gross
FROM #EmployeeTaxes
GROUP BY Payroll
) CK
UNPIVOT
(
    Tax FOR Taxes  IN (SumFIT
                      ,Sum_EE_FICA
                      ,Sum_ER_FICA
                      ,Sum_EE_Medi
                      ,Sum_ER_Medi)

) AS Unpvt

ORDER BY PAYROLL
DROP TABLE #EmployeeTaxes

What I want to do is have the columns that are marked with "_gross" on the end to be in their own separate column as shown by the fake data below

--Fake table that holds structure of desired output
CREATE TABLE #FakeDesiredOutput
(
     Payroll int
    ,Witholding varchar(100)
    ,Tax DECIMAL(19,2)
    ,Gross DECIMAL(19,2)
)
INSERT INTO #FakeDesiredOutput
VALUES (1,'FIT', 300.00, 60000.00)
      ,(1,'Employee_FICA', 450.00, 60000.00)
      ,(1,'Employer_FICA', 150.00, 60000.00)
      ,(1,'Employee_MEDI', 600.00, 60000.00)
      ,(1,'Employer_MEDI', 600.00, 60000.00)
      ,(2,'FIT', 600.00, 75000.00)
      ,(2,'Employee_FICA', 750.00, 75000.00)
      ,(2,'Employer_FICA', 450.00, 75000.00)
      ,(2,'Employee_MEDI', 900.00, 75000.00)
      ,(2,'Employer_MEDI', 900.00, 75000.00) 
      ,(3,'FIT', 900.00, 90000.00)
      ,(3,'Employee_FICA', 1050.00, 90000.00)
      ,(3,'Employer_FICA', 750.00, 90000.00)
      ,(3,'Employee_MEDI', 1200.00, 90000.00)
      ,(3,'Employer_MEDI', 1200.00, 90000.00)

SELECT * FROM #FakeDesiredOutput
DROP TABLE #FakeDesiredOutput
Was it helpful?

Solution

The CROSS APPLY way of doing this would be:

SELECT et.Payroll
    , v.Item
    , Tax = SUM(v.TaxValue)
    , Gross = SUM(v.GrossValue)
FROM #EmployeeTaxes et
CROSS APPLY (
    VALUES ('FIT', fit, fit_Gross, 1)
        , ('Employee_FICA', Employee_FICA, Employee_FICA_Gross, 2)
        , ('Employer_FICA', Employer_FICA, Employer_FICA_Gross, 3)
        , ('Employee_MEDI', Employee_MEDI, Employee_MEDI_Gross, 4)
        , ('Employer_MEDI', Employer_MEDI, Employer_MEDI_Gross, 5)
    )v(Item, TaxValue, GrossValue, OrderByNum)
GROUP BY et.Payroll
    , v.Item
    , v.OrderByNum
ORDER BY et.Payroll
    , v.OrderByNum;

The results:

+---------+---------------+---------+----------+
| Payroll |     Item      |   Tax   |  Gross   |
+---------+---------------+---------+----------+
|       1 | FIT           |  300.00 | 60000.00 |
|       1 | Employee_FICA |  450.00 | 60000.00 |
|       1 | Employer_FICA |  150.00 | 60000.00 |
|       1 | Employee_MEDI |  600.00 | 60000.00 |
|       1 | Employer_MEDI |  600.00 | 60000.00 |
|       2 | FIT           |  600.00 | 75000.00 |
|       2 | Employee_FICA |  750.00 | 75000.00 |
|       2 | Employer_FICA |  450.00 | 75000.00 |
|       2 | Employee_MEDI |  900.00 | 75000.00 |
|       2 | Employer_MEDI |  900.00 | 75000.00 |
|       3 | FIT           |  900.00 | 90000.00 |
|       3 | Employee_FICA | 1050.00 | 90000.00 |
|       3 | Employer_FICA |  750.00 | 90000.00 |
|       3 | Employee_MEDI | 1200.00 | 90000.00 |
|       3 | Employer_MEDI | 1200.00 | 90000.00 |
+---------+---------------+---------+----------+

The CROSS APPLY clause has a fourth column, OrderByNum simply to allow the results to reflect your desired sort order, where FIT comes before the other entries.

OTHER TIPS

Based on your update, I believe the following should work. The CTE allows me to select from your tax records once for each kind of tax.

WITH DesiredRows (TaxNumber, TaxName) AS
(SELECT 1, 'Fit' UNION ALL
 SELECT 2, 'Employee Fica' UNION ALL
 SELECT 3, 'Employer Fica' UNION ALL
 SELECT 4, 'Employee Medi' UNION ALL
 SELECT 5, 'Employer Medi' )
SELECT etx.Payroll,
  dr.TaxNumber, dr.TaxName,
SUM(CASE dr.TaxNumber
   WHEN 1 THEN etx.fit
   WHEN 2 THEN etx.employee_fica
   WHEN 3 THEN etx.Employer_FICA
   WHEN 4 THEN etx.Employee_MEDI
   WHEN 5 THEN etx.Employer_MEDI
   ELSE 0 END) AS Tax,
 SUM(CASE dr.TaxNumber
   WHEN 1 THEN etx.FIT_Gross
   WHEN 2 THEN etx.Employee_FICA_Gross
   WHEN 3 THEN etx.Employer_FICA_Gross
   WHEN 4 THEN etx.Employee_MEDI_Gross
   WHEN 5 THEN etx.Employer_MEDI_Gross
   ELSE 0 END) AS GrossAmt
 FROM dbo.EmployeeTaxes etx
 CROSS JOIN DesiredRows dr
 GROUP BY etx.Payroll, dr.TaxNumber, dr.TaxName
 ORDER BY etx.Payroll, dr.TaxNumber, dr.TaxName
Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top