SQL Add hours for employees - sql

I have a table for employees signing in and out. They have a date and time field for in and out and an PersonID number that links to the employees name etc.
I need to work out the difference between the 2 dates and times then add them all together for each employee.
select a.*,
b.timein,
b.timeout,
datediff(mi,b.timein,b.timeout) as total_mins
from tbl_people a
left join tbl_register b on a.id=b.personid
Output:
+----+-----------+----------+-------------------------+-------------------------+------------+
| ID | FirstName | LastName | TimeIn | TimeOut | Total_Mins |
+----+-----------+----------+-------------------------+-------------------------+------------+
| 1 | David | Test | 2015-05-12 12:11:00.000 | 2015-05-12 12:13:00.000 | 2 |
| 2 | David | Test | 2015-05-12 12:15:00.000 | 2015-05-12 12:18:00.000 | 3 |
+----+-----------+----------+-------------------------+-------------------------+------------+
This is what im currently getting. I would like it to show one record for each person with the total amount of minutes worked.
Thanks in anticipation!

Basically you have at least 2 options:
Option 1 - Use DISTINCT and SUM with OVER clause:
SELECT DISTINCT a.*,
SUM(DATEDIFF(mi, b.timein, b.timeout)) OVER(PARTITION BY a.id) AS total_mins
FROM tbl_people a
LEFT JOIN tbl_register b ON a.id=b.personid
Option 2 - Use a derived table for the GROUP BY part:
SELECT a.*,
total_mins
from tbl_people a
left join (
SELECT personid,
SUM(DATEDIFF(mi, timein, timeout) AS total_mins
FROM tbl_register
GROUP BY personid
) b ON a.id=b.personid

select
ppl.FirstName + ' ' + ppl.LastName as 'Person',
sum( datediff(mi, reg.timein, reg.timeout)) as 'total_mins'
from
tbl_people ppl
left join tbl_register reg on ppl.id = reg.personid
group by
ppl.FirstName + ' ' + ppl.LastName

Related

Sum Group By Column

I have a column (PL.UNITS) that I need to Total at the bottom of the results of a query, is it possible to sum PL.UNITS that is already summed?
Please see query below.
SELECT ID.DUEDATE AS [DUE DATE], CD.RENEWALDATE, CD.RENEWALSTATUS, CD.CONTRACTNUMBER, L.LOCNAME, L.LOCADDRESS1, L.LOCADDRESS2, L.LOCADDRESS3, L.LOCADDRESS4, L.POSTCODE, SUM(PL.UNITS) AS UNITS from CLIENTDETAILS CD
INNER JOIN LOCATIONS L ON CD.CLIENTNUMBER = L.CLIENTNUMBER
INNER JOIN ITEMDETAILS ID ON L.LOCNUMBER = ID.LOCNUMBER
INNER JOIN PLANT PL ON ID.CODE = PL.CODE
WHERE L.OWNER = 210 and L.STATUSLIVE = 1 and ID.DUEDATE > '01/01/2017'
GROUP BY ID.DUEDATE, CD.RENEWALDATE, CD.RENEWALSTATUS, CD.CONTRACTNUMBER, L.LOCNAME, L.LOCADDRESS1, L.LOCADDRESS2, L.LOCADDRESS3, L.LOCADDRESS4, L.POSTCODE
It's probably best to do this sort of thing in front end development. Nevertheless, here is an example (quick and dirty, but shows the idea) for sql-server:
SELECT COALESCE(a.id, 'total') AS id
, SUM(a.thing) AS thing_summed
FROM (
SELECT '1' id
, 1 thing
UNION
SELECT '2'
, 2 thing
UNION
SELECT '1'
, 3 thing
) AS a
GROUP BY ROLLUP(a.id)
Result:
+-------+--------------+
| id | thing_summed |
+-------+--------------+
| 1 | 4 |
| 2 | 2 |
| total | 6 |
+-------+--------------+

Count how many times a value appears in tables SQL

Here's the situation:
So, in my database, a person is "responsible" for job X and "linked" to job Y. What I want is a query that returns: name of person, his ID and he number of jobs it's linked/responsible. So far I got this:
select id_job, count(id_job) number_jobs
from
(
select responsible.id
from responsible
union all
select linked.id
from linked
GROUP BY id
) id_job
GROUP BY id_job
And it returns a table with id in the first column and number of occurrences in the second. Now, what I can't do is associate the name of person to the table. When i put that in the "select" from beginning it gives me all the possible combinations... How can I solve this? Thanks in advance!
Example data and desirable output:
| Person |
id | name
1 | John
2 | Francis
3 | Chuck
4 | Anthony
| Responsible |
process_no | id
100 | 2
200 | 2
300 | 1
400 | 4
| Linked |
process_no | id
101 | 4
201 | 1
301 | 1
401 | 2
OUTPUT:
| OUTPUT |
id | name | number_jobs
1 | John | 3
2 | Francis | 3
3 | Chuck | 0
4 | Anthony | 2
Try this way
select prs.id, prs.name, count(*) from Person prs
join(select process_no, id
from Responsible res
Union all
select process_no, id
from Linked lin ) a on a.id=prs.id
group by prs.id, prs.name
I would recommend aggregating each of the tables by the person and then joining the results back to the person table:
select p.*, coalesce(r.cnt, 0) + coalesce(l.cnt, 0) as numjobs
from person p left join
(select id, count(*) as cnt
from responsible
group by id
) r
on r.id = p.id left join
(select id, count(*) as cnt
from linked
group by id
) l
on l.id = p.id;
select id, name, count(process_no) FROM (
select pr.id, pr.name, res.process_no from Person pr
LEFT JOIN Responsible res on pr.id = res.id
UNION
select pr.id, pr.name, lin.process_no from Person pr
LEFT JOIN Linked lin on pr.id = lin.id) src
group by id, name
order by id
Query ain't tested, give it a shot, but this is the way you want to go

SQL Server - Select Distinct of two columns, where the distinct column selected has a maximum value based on two other columns

I have 2 tables - TC and T, with columns specified below. TC maps to T on column T_ID.
TC
----
T_ID,
TC_ID
T
-----
T_ID,
V_ID,
Datetime,
Count
My current result set is:
V_ID TC_ID Datetime Count
----|-----|------------|--------|
2 | 1 | 2013-09-26 | 450600 |
2 | 1 | 2013-12-09 | 14700 |
2 | 1 | 2014-01-22 | 15000 |
2 | 1 | 2014-01-22 | 15000 |
2 | 1 | 2014-01-22 | 7500 |
4 | 1 | 2014-01-22 | 1000 |
4 | 1 | 2013-12-05 | 0 |
4 | 2 | 2013-12-05 | 0 |
Using the following query:
select T.V_ID,
TC.TC_ID,
T.Datetime,
T.Count
from T
inner join TC
on TC.T_ID = T.T_ID
Result set I want:
V_ID TC_ID Datetime Count
----|-----|------------|--------|
2 | 1 | 2014-01-22 | 15000 |
4 | 1 | 2014-01-22 | 1000 |
4 | 2 | 2013-12-05 | 0 |
I want to write a query to select each distinct V_ID + TC_ID combination, but only with the maximum datetime, and for that datetime the maximum count. E.g. for the distinct combination of V_ID = 2 and TC_ID = 1, '2014-01-22' is the maximum datetime, and for that datetime, 15000 is the maximum count, so select this record for the new table. Any ideas? I don't know if this is too ambitious for a query and I should just handle the result set in code instead.
One method uses row_number():
select v_id, tc_id, datetime, count
from (select T.V_ID, TC.TC_ID, T.Datetime, T.Count,
row_number() over (partition by t.V_ID, tc.tc_id
order by datetime desc, count desc
) as seqnum
from t join
tc
on tc.t_id = t._id
) tt
where seqnum = 1;
The only issue is that some rows have the same maximum datetime value. SQL tables represent unordered sets, so there is no way to determine which is really the maximum -- unless the datetime really has a time component or another column specifies the ordering within a day.
It is possible to solve this using CTEs. First, extracting the data from your query. Second, get the maxdates. Third, get the highest count for each maxdate.:
;WITH Dataset AS
(
select T.V_ID,
TC.TC_ID,
T.[Datetime],
T.[Count]
from T
inner join TC
on TC.T_ID = T._ID
),
MaxDates AS
(
SELECT V_ID, TC_ID, MAX(t.[Datetime]) AS MaxDate
FROM Dataset t
GROUP BY t.V_ID, t.TC_ID
)
SELECT t.V_ID, t.TC_ID, t.[Datetime], MAX(t.[Count]) AS [Count]
FROM Dataset t
INNER JOIN MaxDates m ON t.V_ID = m.V_ID AND t.TC_ID = m.TC_ID AND m.MaxDate = t.[Datetime]
GROUP BY t.V_ID, t.TC_ID, t.[Datetime]
Just to keep it simple:
You need to group by T.V_ID,TC.TC_ID,
with selecting the max of date and then to get the maximum count, you must use a sub query as follows,
select T.V_ID,
TC.TC_ID,
max(T.Datetime) as Date_Time,
(select max(Count) from T as tb where v_ID = T.v_ID and DateTime = max(T.DateTime)) as Count
from T
inner join TC
on TC.T_ID = T._ID
group by T.V_ID,TC.TC_ID,

SQL Group By Issue with same item ID

I am trying to track the total number of sales a rep has along with the amount of time he was clocked into work.
I have the following two tables:
table1:
employeeID | item | price | timeID
----------------------------------------
1 | 1 | 12.92 | 123
1 | 2 | 10.00 | 123
1 | 2 | 10.00 | 456
table2:
ID | minutes_in_shift
--------------------------
123 | 45
456 | 15
I would join these two queries with the following SQL:
SELECT
t1.employeeID, t1.item, t1.price, t1.shiftID, t2.minutes_in_shift
FROM table1 t1
JOIN table 2 t2 ON (t2.ID = t1.timeID)
Which would return the following table:
employeeID | item | price | timeID | minutes_in_shift
---------------------------------------------------
1 | 1 | 12.92 | 123 | 45
1 | 2 | 10.00 | 123 | 45
1 | 2 | 10.00 | 456 | 15
I would like for the consolidate results, however, to have this outcome:
employeeID | itemsSold | priceTotals | totaltimeworked
-----------------------------------------------------------------
1 | 3 | 32.92 | 60
I could use COUNT and SUM for the items and price but I cannot figure out how to properly show the total time worked in the manner it appears above.
Note: I am only having trouble with calculating the time worked. In shift 123 - employee 1 was working 45 minutes, regardless of how many items he sold.
Any suggestions?
If you wish to use the sample data as they are you will need to extract the shifts and sum the minutes, like this:
with a as (
select employeeID, count(*) itemsSold, sum(price) priceTotals
from Sampletable1
group by employeeID),
b as (
select employeeID, shiftID, max(minutes_in_shift) minutes_in_shift
from Sampletable1
group by employeeID, shiftID),
c as (
select employeeID, sum(minutes_in_shift) totaltimeworked
from b
group by employeeID)
select a.employeeID, a.itemsSold, a.priceTotals, c.totaltimeworked
from a inner join c on a.employeeID = c.employeeID
However, with your existing tables the select statement will be much easier:
with a as (
select employeeID, timeID, count(*) itemsSold, sum(price) priceTotals
from table1
group by employeeID, timeID)
select a.employeeID, sum(a.itemsSold), sum(a.priceTotals), sum(table2.minutes_in_shift) totaltimeworked
from a inner join table2 on a.timeID = table2.ID
group by a.employeeID
I think this query should do what you want:
SELECT t1.employeeID,
count(t1.item) AS itemsSold,
sum(t1.price) AS priceTotals,
sum(DISTINCT t2.minutes_in_shift) AS totaltimeworked
FROM table1 t1
JOIN table2 t2 ON (t2.ID = t1.timeID)
GROUP BY t1.employeeID;
Check on SQL Fiddle

Select distinct where date is max

This feels really stupid to ask, but i can't do this selection in SQL Server Compact (CE)
If i have two tables like this:
Statuses Users
id | status | thedate id | name
------------------------- -----------------------
0 | Single | 2014-01-01 0 | Lisa
0 | Engaged | 2014-01-02 1 | John
1 | Single | 2014-01-03
0 | Divorced | 2014-01-04
How can i now select the latest status for each person in statuses?
the result should be:
Id | Name | Date | Status
--------------------------------
0 | Lisa | 2014-01-04 | Divorced
1 | John | 2014-01-03 | Single
that is, select distinct id:s where the date is the highest, and join the name. As bonus, sort the list so the latest record is on top.
In SQL Server CE, you can do this using a join:
select u.id, u.name, s.thedate, s.status
from users u join
statuses s
on u.id = s.id join
(select id, max(thedate) as mtd
from statuses
group by id
) as maxs
on s.id = maxs.id and s.thedate = maxs.mtd;
The subquery calculates the maximum date and uses that as a filter for the statuses table.
Use the following query:
SELECT U.Id AS Id, U.Name AS Name, S.thedate AS Date, S.status AS Status
FROM Statuses S
INNER JOIN Users U on S.id = U.id
WHERE S.thedate IN (
SELECT MAX(thedate)
FROM statuses
GROUP BY id);