2

I have a problem with my SQL queries (I know I'm very bad at this task :( )

Using SLQ Server 2014, I've got a table that stores bank days containing the name of the day and a datetime.

On the other hand there's a table with technicians that has worked over a project. They could work regular days or even those bank days.

I get a query in order to generate payrolls that get all of those technicians that have worked getting techcode, name, project id and date but I need to get another list (UNION) for those all tehcnicians that have not worked during bank holidays because they also need to be inlcuded in the report for payroll (bank days are payed as well but need to be differentiate).

I tried with joins to get that list that should contain tech code, name, project id and date from Holidays if they didn't work that day (that info is retrieved in the first query because is stored in the Sessions table. The only value that have both tables in common is the date.

I'll give you my queries so far:

-- To get real work hours / days within date range

select 
    distinct s.TechnicianCode, t.Name, s.JobProjectId as jobId, 
    s.SignInDate as [date], 'w'
from 
    JobSession s
inner join 
    Technician t on t.TechnicianCode = s.TechnicianCode
inner join 
    JobAssignedTech jt on jt.TechCode = s.TechnicianCode
left join 
    LeaveDate ld on ld.TechnicianCode = s.TechnicianCode
where  
    (cast(s.SignInDate as date) >= cast(@DateFrom as date) 
    and cast(s.SignInDate as date) <= cast(@DateTo as date)) 
    and jt.IsActive = 1

Holidays contains:

HolidayID   HolidayDate Name.....   
3   2015-08-19 00:00:00.000 August Bank Holiday ...
5   2015-08-20 00:00:00.000 August Bank Holiday ...

For example, for a query like this

select  
    distinct s.TechnicianCode, t.Name, s.JobProjectId, s.SignInDate  
from 
    JobSession s
inner join 
    Technician t on s.TechnicianCode = t.TechnicianCode 
where 
    cast(s.SignInDate as date) between cast('2015/08/17' as date) and cast('2015/08/24' as date)   

I get

TechnicianCode  Name                JobProjectId            SignInDate
    282                 Patrick Flood       TEST JOB CHQ E2443      2015-08-17          
    332                 Anthony Farrell     TEST JOB CHQ E2443      2015-08-17
    342                 Ciaran Kimmage      TEST JOB CHQ E2443      2015-08-17
    343                 Anthony Clinton     TEST JOB CHQ E2443      2015-08-17
    440                 Darragh Byrne       TEST JOB CHQ E2443      2015-08-17
    440                 Darragh Byrne       TEST JOB CHQ E2443      2015-08-20
    489                 Thomas Cunningham   TEST JOB CHQ E2443      2015-08-17
    491                 Aidan Lee           TEST JOB CHQ E2443      2015-08-17
    497                 Brian Canavan       TEST JOB CHQ E2443      2015-08-17
    TE                  Test                Sandyford site 07.15    2015-08-17

So I would need to get a list showing those technicians but date should be bank holidays date and only if they didn't work during those days so, for example, technician with code 440 must not be in the list twice because he worked on the 20th of August and it should looks like this:

TechnicianCode  Name                JobProjectId            SignInDate
        282                 Patrick Flood       TEST JOB CHQ E2443      2015-08-19          
        282                 Patrick Flood       TEST JOB CHQ E2443      2015-08-20          
        332                 Anthony Farrell     TEST JOB CHQ E2443      2015-08-19
        332                 Anthony Farrell     TEST JOB CHQ E2443      2015-08-20
        342                 Ciaran Kimmage      TEST JOB CHQ E2443      2015-08-19
        342                 Ciaran Kimmage      TEST JOB CHQ E2443      2015-08-20
        343                 Anthony Clinton     TEST JOB CHQ E2443      2015-08-19
        343                 Anthony Clinton     TEST JOB CHQ E2443      2015-08-20
        440                 Darragh Byrne       TEST JOB CHQ E2443      2015-08-19        
        489                 Thomas Cunningham   TEST JOB CHQ E2443      2015-08-19
        489                 Thomas Cunningham   TEST JOB CHQ E2443      2015-08-20
        491                 Aidan Lee           TEST JOB CHQ E2443      2015-08-19
        491                 Aidan Lee           TEST JOB CHQ E2443      2015-08-20
        497                 Brian Canavan       TEST JOB CHQ E2443      2015-08-19
        497                 Brian Canavan       TEST JOB CHQ E2443      2015-08-19
        TE                  Test                Sandyford site 07.15    2015-08-19
        TE                  Test                Sandyford site 07.15    2015-08-20

I have tried with UNION, SUB QUERIES, EXIST, IN, INNER and so on I get nothing like that :-/

A little help will be so thankful.

bitsdisasters
  • 253
  • 5
  • 14
  • 3
    DISTINCT is not a function on a column, it works on the whole selected rows!!! (I.e "select distinct (c1), c2" eq "select distinct c1, c2" eq "select distinct c1, (c2)"... (It's actually SELECT DISTINCT, as the opposite to SELECT [ALL].) – jarlh Aug 27 '15 at 11:47
  • 1
    I have to repeat this as well. `DISTINCT` is ***NOT*** a function. Also: which DBMS are you using? Postgres? Oracle? –  Aug 27 '15 at 11:59
  • where is the join with Holidays? – Florin Ghita Aug 27 '15 at 13:53
  • The only join is available is trough datetime (casting as date). The goal is getting a whole list with techs that have worked (date is stored into session) and haven't worked (there's no data stored, they just have no session for that day so no info available and I have to build using holiday date. – bitsdisasters Aug 27 '15 at 14:20

2 Answers2

0

You can do this in a UNION statement, which connects all technicians to all holidays in the range, but then uses a LEFT JOIN to look up technicians who worked on the holiday and then filters them out if they did.

See below:

select  distinct 
    s.TechnicianCode, 
    t.Name, 
    s.JobProjectId, 
    s.SignInDate  
from 
    JobSession s
inner join 
    Technician t on s.TechnicianCode = t.TechnicianCode 
where 
    cast(s.SignInDate as date) between cast('2015/08/17' as date) and cast('2015/08/24' as date) 

UNION 

SELECT 
    t.TehnicianCode,
    t.Name,
    NULL AS JobProjectID,
    h.HolidayDate 
FROM 
    Technician t 
     INNER JOIN 
    Holidays h ON 
        h.HolidayDate BETWEEN cast('2015/08/17' as date) and cast('2015/08/24' as date) -- connect every technician to every holiday in the range
     LEFT JOIN 
    JobSession s ON -- check for technicians who worked on the holiday
        t.TechnicianCode = s.TechnicianCode AND 
        cast(s.SignInDate as date) = h.HolidayDate
WHERE s.TechnicianCode IS NULL -- filter out the technicans who worked on the holiday
AHiggins
  • 7,029
  • 6
  • 36
  • 54
  • Thank you very much for your help. It worked!. I also found the solution; I was nearly there before but made a mistake with the conditions. – bitsdisasters Aug 28 '15 at 08:31
0

Well, I finally managed to get the solution (not so difficult for anyone who knows a bit about SQL but a great one for a newcomer like me.

To get only techs who have not been working during bank holidays I had to use "NOT EXISTS" in the second part of the UNION:

select distinct(s.TechnicianCode), t.Name, jt.JobProjectId as jobId, cast(h.HolidayDate as date) as date, 'h'---this is to know if tech has worked or was on holidays
        from Holidays h, JobSession s
        inner join Technician t  on s.TechnicianCode = t.TechnicianCode
        inner join JobAssignedTech jt on jt.TechCode = t.TechnicianCode
        where cast(h.HolidayDate as date)  between cast(@DateFrom as date) and cast(@DateTo as date) 
            and cast(s.SignInDate as date)  between cast(@DateFrom as date) and cast(@DateTo as date) 
            and jt.IsActive = 1
            and  not exists (
        Select *--, JobProjectId, SignInDate , h.HolidayDate, h.Name
         from JobSession s1
             where cast(s1.SignInDate as date)  between cast(@DateFrom as date) and cast(@DateTo as date)    
             and s1.TechnicianCode = s.TechnicianCode and cast(s1.SignIndate as date) = cast(h.HolidayDate as date)
         )
bitsdisasters
  • 253
  • 5
  • 14