Home > Enterprise >  SQL Sum over several columns of an entry with ad hoc created columns
SQL Sum over several columns of an entry with ad hoc created columns

Time:04-09

I have the following table, like:

woker date amount
jeff 04-04-2022 4.00
jeff 04-05-2022 2.00
jeff 04-08-2022 3.50
dave 04-04-2022 1.00
dave 04-07-2022 6.50

It contains the date and the amount of hours worked by a worker.

Now I want to create a table like the following with a select to show hours per weekday. The column "count" should represent the amount of days where the worker has hours. The column "sum" should sum the hours for this week. So the final result should be like this:

worker mon tue wed thu fri sat sun count sum
jeff 4.00 2.00 null null 3.50 null null 3 9.50
dave 1.00 null null 6.50 null null null 2 7.50

My statement so far is:

SELECT worker,
CASE WHEN DATEPART(weekday,date) = 1 THEN amount END AS mon,
CASE WHEN DATEPART(weekday,date) = 2 THEN amount END AS tue,
CASE WHEN DATEPART(weekday,date) = 3 THEN amount END AS wed,
CASE WHEN DATEPART(weekday,date) = 4 THEN amount END AS thu,
CASE WHEN DATEPART(weekday,date) = 5 THEN amount END AS fri,
CASE WHEN DATEPART(weekday,date) = 6 THEN amount END AS sat,
CASE WHEN DATEPART(weekday,date) = 7 THEN amount END AS sun
FROM table

So now I need help to get the last two columns. Can anybody explain, how to sum up / count values over multiple columns withi one entry?

Thank you.

CodePudding user response:

Conditional aggregation is an option (don't forget to set the first day of the week using SET DATEFIRST):

SET DATEFIRST 1

SELECT 
   worker,
   SUM(CASE WHEN DATEPART(weekday, date) = 1 THEN amount END) AS mon,
   SUM(CASE WHEN DATEPART(weekday, date) = 2 THEN amount END) AS tue,
   SUM(CASE WHEN DATEPART(weekday, date) = 3 THEN amount END) AS wed,
   SUM(CASE WHEN DATEPART(weekday, date) = 4 THEN amount END) AS thu,
   SUM(CASE WHEN DATEPART(weekday, date) = 5 THEN amount END) AS fri,
   SUM(CASE WHEN DATEPART(weekday, date) = 6 THEN amount END) AS sat,
   SUM(CASE WHEN DATEPART(weekday, date) = 7 THEN amount END) AS sun,
   COUNT(DISTINCT DATEPART(weekday, date)) AS [count],
   SUM(amount) AS [sum]
FROM (VALUES
   ('jeff', CONVERT(date, '20220404'), 4.00),
   ('jeff', CONVERT(date, '20220405'), 2.00),
   ('jeff', CONVERT(date, '20220408'), 3.50),
   ('dave', CONVERT(date, '20220404'), 1.00),
   ('dave', CONVERT(date, '20220407'), 6.50)
) t (worker, date, amount)
GROUP BY worker
ORDER BY worker

Result:

worker mon tue wed thu fri sat sun count sum
dave 1.00 6.50 2 7.50
jeff 4.00 2.00 3.50 3 9.50

CodePudding user response:

We use the function SUM so as to be able to agregate the different lines. We add the week number in the SELECT and the GROUP BY so as to separate the weeks and know which week of the year we are looking at. We could also add the year if the same table will be used for long enough.

SET DATEFIRST 1;
SELECT 
  DATEPART(week, date) AS "week",
  worker,
  CASE WHEN DATEPART(weekday,date) = 1 THEN amount END ) AS mon,
  SUM( CASE WHEN DATEPART(weekday,date) = 2 THEN amount END ) AS tue,
  SUM( CASE WHEN DATEPART(weekday,date) = 3 THEN amount END ) AS wed,
  SUM( CASE WHEN DATEPART(weekday,date) = 4 THEN amount END ) AS thu,
  SUM( CASE WHEN DATEPART(weekday,date) = 5 THEN amount END ) AS fri,
  SUM( CASE WHEN DATEPART(weekday,date) = 6 THEN amount END ) AS sat,
  SUM( CASE WHEN DATEPART(weekday,date) = 7 THEN amount END ) AS sun,
  COUNT(DISTINCT DATEPART(weekday,date) ) AS "count",
amount AS "sum"
FROM table
GROUP BY 
  DATEPART(week, date),
  worker
ORDER BY 
  DATEPART(week, date),
  worker;
  • Related