Baldie47
Baldie47

Reputation: 1254

select in different columns based on condition

this query is a bit more complicated, but for simplicity reasons I'll post it as simple as possible

I have 1 table that has following columns

table: "time_TimesheetRow" columns:

TimeSheet_ID,
d1,
d2,
d3,
d4,
d5,
d6,
d7,
rate

now, my select brings a lot of fields, among those I have the fields:

   time_TimesheetRow.d3 AS [Monday Normal Hours], 
   time_TimesheetRow.d4 AS [Tuesday Normal Hours], 
   time_TimesheetRow.d5 AS [Wednesday Normal Hours], 
   time_TimesheetRow.d6 AS [Thursday Normal Hours], 
   time_TimesheetRow.d7 AS [Friday Normal Hours], 
   time_TimesheetRow.d1 AS [Saturday Normal Hours], 
   time_TimesheetRow.d2 AS [Sunday Normal Hours], 
   time_TimesheetRow.d3 AS [Monday OT Hours], 
   time_TimesheetRow.d4 AS [Tuesday OT Hours], 
   time_TimesheetRow.d5 AS [Wednesday OT Hours], 
   time_TimesheetRow.d6 AS [Thursday OT Hours], 
   time_TimesheetRow.d7 AS [Friday OT Hours], 
   time_TimesheetRow.d1 AS [Saturday OT Hours], 
   time_TimesheetRow.d2 AS [Sunday OT Hours]

but, the thing is that all normal hours are the ones with rate = 0 and the OT columns are the ones with rate <> 0

how should I do to bring this?

I was trying adding the same table with different alias in the FROM clause and then using the ID field for matching them, but doesn't seems to work

this is the complete query, this will give a clear example.

SELECT ts1.TimeSheetRow_ID AS [Unique Line Id], 
       peperson.PERSONNEL_NO AS [Staff Id], 
       peperson.SURNAME + ', ' + peperson.FORENAME AS [Forename + Surname], 
       time_Timesheet.TSDate AS [Week ending date], 
       ts2.d1 + ts2.d2 + ts2.d3 + ts2.d4 + ts2.d5 + ts2.d6 + ts2.d7 AS [Normal Hours], 
       ts3.d1 + ts3.d2 + ts3.d3 + ts3.d4 + ts3.d5 + ts3.d6 + ts3.d7 AS [Overtime Hours], 
       ts2.d1 + ts2.d2 + ts2.d3 + ts2.d4 + ts2.d5 + ts2.d6 + ts2.d7 + ts3.d1 + ts3.d2 + ts3.d3 + ts3.d4 + ts3.d5 + ts3.d6 + ts3.d7 AS [Total Hours],
       CASE
           WHEN ts1.Rate = 11
           THEN 'Unpaid'
           ELSE 'Paid'
       END AS [Overtime Paid/Unpaid Indicator], 
       ts1.notes AS Narrative, 
       ts1.Job AS [Job Number], 
       ts2.d3 AS [Monday Normal Hours], 
       ts2.d4 AS [Tuesday Normal Hours], 
       ts2.d5 AS [Wednesday Normal Hours], 
       ts2.d6 AS [Thursday Normal Hours], 
       ts2.d7 AS [Friday Normal Hours], 
       ts2.d1 AS [Saturday Normal Hours], 
       ts2.d2 AS [Sunday Normal Hours], 
       ts3.d3 AS [Monday OT Hours], 
       ts3.d4 AS [Tuesday OT Hours], 
       ts3.d5 AS [Wednesday OT Hours], 
       ts3.d6 AS [Thursday OT Hours], 
       ts3.d7 AS [Friday OT Hours], 
       ts3.d1 AS [Saturday OT Hours], 
       ts3.d2 AS [Sunday OT Hours], 
       peperson.hourly_rate AS [Staff Overhead Rate], 
       peperson.hourly_rate AS [Cost Rate], 
       peperson.PU AS [Staff Cost Centre Code], 
       peperson.PU_DESCRIPTION AS [Staff Cost Centre Name]
FROM dbo.time_manager
     INNER JOIN dbo.peperson peperson_manager ON dbo.time_manager.manager_payroll = peperson_manager.Personnel_no
     RIGHT OUTER JOIN dbo.time_Timesheet
     INNER JOIN dbo.time_TimesheetRow ts1 ON dbo.time_Timesheet.TimeSheet_ID = ts1.TimeSheet_ID
     INNER JOIN dbo.time_TimesheetRow ts2 ON dbo.time_Timesheet.TimeSheet_ID = ts2.TimeSheet_ID
                                             AND ts2.rate IN(0)
     INNER JOIN dbo.time_TimesheetRow ts3 ON dbo.time_Timesheet.TimeSheet_ID = ts3.TimeSheet_ID
                                             AND ts3.rate NOT IN(0)
     INNER JOIN dbo.peperson ON dbo.time_Timesheet.Payroll = dbo.peperson.Personnel_no
     INNER JOIN dbo.time_Status ON dbo.time_Timesheet.StatusID = dbo.time_Status.statusID ON dbo.time_manager.payroll = dbo.time_Timesheet.Payroll
WHERE time_Timesheet.TSDate > '2019-11-01'
      AND ts1.Job LIKE 'B23639%';

right now it seems taht something is wrong with the query since is bringing too few rows, when it should be bringing more data, I take out the joins with the dbo.time_TimesheetRow ts2 and dbo.time_TimesheetRow ts3 tables and it brings a lot more, so I'm thinking here is where the error lays

Added with logic proposed by @LukStorms :

SELECT ts1.TimeSheetRow_ID AS [Unique Line Id], 
       peperson.PERSONNEL_NO AS [Staff Id], 
       peperson.SURNAME + ', ' + peperson.FORENAME AS [Forename + Surname], 
       time_Timesheet.TSDate AS [Week ending date], 
       ts1.d1 + ts1.d2 + ts1.d3 + ts1.d4 + ts1.d5 + ts1.d6 + ts1.d7 AS [Normal Hours], 
       ts2.d1 + ts2.d2 + ts2.d3 + ts2.d4 + ts2.d5 + ts2.d6 + ts2.d7 AS [Overtime Hours], 
       ts1.d1 + ts1.d2 + ts1.d3 + ts1.d4 + ts1.d5 + ts1.d6 + ts1.d7 + ts2.d1 + ts2.d2 + ts2.d3 + ts2.d4 + ts2.d5 + ts2.d6 + ts2.d7 AS [Total Hours],
       CASE
           WHEN ts1.Rate = 11
           THEN 'Unpaid'
           ELSE 'Paid'
       END AS [Overtime Paid/Unpaid Indicator], 
       ts1.notes AS Narrative, 
       ts1.Job AS [Job Number], 
       ts1.d3 AS [Monday Normal Hours], 
       ts1.d4 AS [Tuesday Normal Hours], 
       ts1.d5 AS [Wednesday Normal Hours], 
       ts1.d6 AS [Thursday Normal Hours], 
       ts1.d7 AS [Friday Normal Hours], 
       ts1.d1 AS [Saturday Normal Hours], 
       ts1.d2 AS [Sunday Normal Hours], 
       ts2.d3 AS [Monday OT Hours], 
       ts2.d4 AS [Tuesday OT Hours], 
       ts2.d5 AS [Wednesday OT Hours], 
       ts2.d6 AS [Thursday OT Hours], 
       ts2.d7 AS [Friday OT Hours], 
       ts2.d1 AS [Saturday OT Hours], 
       ts2.d2 AS [Sunday OT Hours], 
       peperson.hourly_rate AS [Staff Overhead Rate], 
       peperson.hourly_rate AS [Cost Rate], 
       peperson.PU AS [Staff Cost Centre Code], 
       peperson.PU_DESCRIPTION AS [Staff Cost Centre Name]
FROM dbo.time_manager
     INNER JOIN dbo.peperson peperson_manager ON dbo.time_manager.manager_payroll = peperson_manager.Personnel_no
     RIGHT OUTER JOIN dbo.time_Timesheet
     INNER JOIN dbo.time_TimesheetRow ts1 ON dbo.time_Timesheet.TimeSheet_ID = ts1.TimeSheet_ID
                                             AND ts1.Rate = 0
     LEFT JOIN dbo.time_TimesheetRow ts2 ON dbo.time_Timesheet.TimeSheet_ID = ts2.TimeSheet_ID
                                            AND ts2.rate > 0
     INNER JOIN dbo.peperson ON dbo.time_Timesheet.Payroll = dbo.peperson.Personnel_no
     INNER JOIN dbo.time_Status ON dbo.time_Timesheet.StatusID = dbo.time_Status.statusID ON dbo.time_manager.payroll = dbo.time_Timesheet.Payroll
WHERE time_Timesheet.TSDate > '2019-11-01'
      AND ts1.Job LIKE 'B23639%';

I still have the issue that the Overtime Hours, Total Hours, and all the OT Hours columns are showing NULL as value

Upvotes: 1

Views: 80

Answers (2)

LukStorms
LukStorms

Reputation: 29647

So you want to self-join based on the id and the rate

SELECT 
t0.TimeSheet_ID,
t0.d3 AS [Monday Normal Hours], 
t0.d4 AS [Tuesday Normal Hours], 
t0.d5 AS [Wednesday Normal Hours], 
t0.d6 AS [Thursday Normal Hours], 
t0.d7 AS [Friday Normal Hours], 
t0.d1 AS [Saturday Normal Hours], 
t0.d2 AS [Sunday Normal Hours], 
SUM(tx.d3) AS [Monday OT Hours], 
SUM(tx.d4) AS [Tuesday OT Hours], 
SUM(tx.d5) AS [Wednesday OT Hours], 
SUM(tx.d6) AS [Thursday OT Hours], 
SUM(tx.d7) AS [Friday OT Hours], 
SUM(tx.d1) AS [Saturday OT Hours], 
SUM(tx.d2) AS [Sunday OT Hours]
FROM time_TimesheetRow t0
LEFT JOIN time_TimesheetRow tx
  ON tx.TimeSheet_ID = t0.TimeSheet_ID
 AND tx.rate > 0
WHERE t0.rate = 0
GROUP BY t0.TimeSheet_ID, t0.d1, t0.d2, t0.d3, t0.d4, t0.d5, t0.d6, t0.d7
ORDER BY t0.TimeSheet_ID

An untested notepad scribble that's based of a remodelled version of the unsimplified query:

SELECT 
   ts.TimeSheetRow_ID AS [Unique Line Id], 
   pep.PERSONNEL_NO AS [Staff Id], 
   CONCAT(pep.SURNAME, ', ' + pep.FORENAME) AS [Forename + Surname], 
   ts.TSDate AS [Week ending date], 
   t0tot.Total AS [Normal Hours], 
   ISNULL(txtot.Total,0) AS [Overtime Hours], 
   t0tot.Total + ISNULL(txtot.Total,0) AS [Total Hours],
   CASE WHEN ts.Rate = 11 THEN 'Unpaid' ELSE 'Paid' END AS [Overtime Paid/Unpaid Indicator],
   t0.notes AS [Narrative], 
   t0.Job AS [Job Number],
   t0.d3 AS [Monday Normal Hours], 
   t0.d4 AS [Tuesday Normal Hours], 
   t0.d5 AS [Wednesday Normal Hours], 
   t0.d6 AS [Thursday Normal Hours], 
   t0.d7 AS [Friday Normal Hours], 
   t0.d1 AS [Saturday Normal Hours], 
   t0.d2 AS [Sunday Normal Hours], 
   tx.d3 AS [Monday OT Hours], 
   tx.d4 AS [Tuesday OT Hours], 
   tx.d5 AS [Wednesday OT Hours], 
   tx.d6 AS [Thursday OT Hours], 
   tx.d7 AS [Friday OT Hours], 
   tx.d1 AS [Saturday OT Hours], 
   tx.d2 AS [Sunday OT Hours], 
   pep.hourly_rate AS [Staff Overhead Rate], 
   pep.hourly_rate AS [Cost Rate], 
   pep.PU AS [Staff Cost Centre Code], 
   pep.PU_DESCRIPTION AS [Staff Cost Centre Name]
FROM dbo.time_Timesheet AS ts
INNER JOIN dbo.time_manager AS tm_mngr
  ON tm_mngr.payroll = ts.Payroll
INNER JOIN dbo.peperson AS pep_mngr
  ON pep_mngr.Personnel_no = tm_mngr.manager_payroll
INNER JOIN dbo.peperson AS pep 
  ON pep.Personnel_no = ts.Payroll
INNER JOIN dbo.time_Status AS tm_stat
  ON tm_stat.statusID = ts.StatusID
INNER JOIN dbo.time_TimesheetRow AS t0
  ON t0.TimeSheet_ID = ts.TimeSheet_ID
 AND t0.Rate = 0
LEFT JOIN dbo.time_TimesheetRow tx
  ON tx.TimeSheet_ID = ts.TimeSheet_ID 
 AND (tx.rate > 0 OR tx.rate IS NULL)
OUTER APPLY (SELECT SUM(d) Total FROM (VALUES (t0.d1),(t0.d2),(t0.d3),(t0.d4),(t0.d5),(t0.d6),(t0.d7)) t(d)) AS t0tot
OUTER APPLY (SELECT SUM(d) Total FROM (VALUES (tx.d1),(tx.d2),(tx.d3),(tx.d4),(tx.d5),(tx.d6),(tx.d7)) t(d)) AS txtot
WHERE ts.TSDate > '2019-11-01'
  AND t0.Job LIKE 'B23639%';

Basically, more use of short alias names.
And not using a RIGHT JOIN, since that's often confusing.
And outer applies to sum the d's.

Upvotes: 1

Seichelis
Seichelis

Reputation: 35

the lines in your select

INNER JOIN dbo.time_TimesheetRow ts2 ON dbo.time_Timesheet.TimeSheet_ID = ts2.TimeSheet_ID
                                         AND ts2.rate IN(0)
INNER JOIN dbo.time_TimesheetRow ts3 ON dbo.time_Timesheet.TimeSheet_ID = ts3.TimeSheet_ID
                                         AND ts3.rate NOT IN(0)

narrows your result set, as inner join requires all set items should be included on joined column from both sides and you limiting set with

rate (NOT) IN(0)

this means only the results having such values will be added to set.

inner join Vien diagram

I would suggest using left or right join as not all your rows would have rate "in (0)" or "in not (0)" for all data.

And I am not so sure you know what you doing because adding right outer join in the middle of the query seems unusual as later you adding left join.

For your problem with Overtime Hours, Total Hours, and all the OT Hours use ISNULL(value,0) before adding it, you can check it with

select 1+null+1

sum of NULL and digit is always NULL

Upvotes: 1

Related Questions