Get employees that were active during specific date range - sql

How do I get list of active employees who were active in a specific date range (1-JAN-2014 TO 31-MAR-2014)
My table is like
Table:
employeeheader
empid
firstname
lastname
emphistory
empid
begindate
enddate
If enddate is null that means employee is still active.

SELECT * FROM employeeheader
JOIN emphistory ON employeeheader.empid = emphistory.empid
WHERE begindate <= <range_start> AND (enddate is null OR enddate >= <range_end>)
This gives all the employees which worked completely during a specific range.

Something like this might work - I didn't actually test it.
where begindate < the day after your end date
and nvl(enddate, sysdate) >= your start date
Since oracle dates include the time of day, you want to account for it, just in case.

This query can help
SELECT * FROM employeeheader
WHERE empid IN
(SELECT empid FROM emphistory
WHERE (enddate IS NULL OR enddate>= EndDateParameter)
AND begindate<=BeginDateParameter)

Related

How to calculate the total numbers of employees available as at a specific day given their date of entry?

I am using SQL Server 2012 and I have a table in my database called Employee.
Assuming it has only 3 columns, namely EmpID, Dept, DateOfEntry, Date Left, what would be the SQL query syntax that will give the count of employees as at, say, 2017-05-31
Each row in the table represents a single employee.
Here is how the Employee Table stands:
EmpId Dept DateOfEntry DateLeft
100 F&B 2015-06-05 2016-01-02
125 Kitchen 2016-02-12 2016-03-10
151 Finance 2018-05-03 NULL
...
UPDATE: Apologies for missing the DateLeft column in the above table. I have updated the question accordingly.
It seems that the OP isn't going to post their attempt.
This is a very simple query, and with a bit of a Google/Bing/Yahoo you probably would have found the syntax on how to use a WHERE clause with Greater Than (>) and Less Than (<) expressions. Anyway, the answer you want is:
DECLARE #Date date;
SET #Date = '20170531';
SELECT COUNT(*) AS Employees
FROM YourTable
WHERE DateOfEntry <= #Date
AND (DateLeft > #Date --I assume that they are no longer emplyed on the day they leave, other use >=
OR DateLeft IS NULL);
select count(*),dept from employee where '31-may-2017'>DateOfEntry
and '31_-may-2017'<DateOfLeft group by dept;
If you want at in single date than try this:
select count(EmpID) from employee
where DateOfEntry>='31-may-2017' and (dateleft is null or dateleft< getdate())
You would count the employees who are at work as of that date, right? Meaning they should have entered on or BEFORE that day:
select count(*)
from employees
where DateOfEntry <= '20170531' and
(dateLeft is null OR dateLeft >= '20170531');
Note: If you wouldn't accept the person as at work on her\his dateLeft then change >= to >.

Decide if an employee is new or leavingemployee

I have employees with contracts in the database. I want to know if an employee is a new employee at a location. I have the following datastructure:
EmployeeId Index BeginDate Enddate HoursToWork LocationId
12133 1 2013-01-01 2014-01-01 10 1
12133 2 2013-06-01 2014-01-01 20 1
12133 3 2012-01-01 2014-01-01 5 1
As you can see, an employee can have more than 1 contract on a location. Then Endate can be null.
Per location and per Month or Quarter I want to see how many employees are started. I want to use #Startdate and #Enddate parameters for the period I want have the data.
There are to many cases I should take into account. Like, the Index field is not Always increased together with the Begindate, like you can see at Index = 3.
Example:
I want to know how many employees are started in january 2013.
In this case nothing because the first contract was started on 2012-01-01. There are two new contracts but this employee is not new for the location. But if index 3 was not existing then whis should be a new employee.
It can be that a employee have two contract that starts on the same date and if he doesnt have before a contract then it is 1 new employee.
I already tried the following, which works when an employee just has 1 contract. But if there are more than 1 contracts then it is hard to decide if the employee is new:
declare #Startdate datetime set #Startdate = '2013-01-01'
declare #Enddate datetime set #Enddate = '2013-12-31'
select EmployeeId, Index, BeginDate, Enddate, HoursToWork, LocationId
,(case
when BeginDate between #Startdate and #Enddate then 1
end) as NewEmployee
,(case
when Enddate between #Startdate and #Enddate then 1
end) as LeavingEmployee
from Contracts
Given the 3 records, this employee is not an new employee. I would like to have a output like:
LocationId NewEmployee
1 0
When I just have the first 2 records and I want know new employees in Janury 2013 then I expect:
LocationId NewEmployee
1 1
How about something like this for starting employee?
SELECT EmployeeID, LocationID, Min(StartDate)
FROM Contracts
GROUP BY EmployeeID, LocationID
HAVING Min(StartDate) between #Startdate and #Enddate
I would suggest something similar for Leavingemployee, but I would not spend much effort trying to get those into one query. It seems they are functionally different.
edit: es, it should be Min, not max. As for what is needed, i read "I want to see how many employees are started", and i didn't see much reason to complicate matters.
If additional data is needed, it's always possible to move this to a subquery and select * where ... in subquery, but if it's not needed...
In order to only deal with active contract (contracts that are active during the time interval for the query) we can set the following rules:
A contract is active somewhere during the period we are looking at if its startdate < the parameter enddate and its enddate > the parameter startdate.
Adding that to our query, we get
SELECT EmployeeID, LocationID, Min(StartDate)
FROM Contracts
WHERE Startdate <= #Enddate
AND Enddate >= #Startdate
GROUP BY EmployeeID, LocationID
HAVING Min(StartDate) between #Startdate and #Enddate

Checking for date range conflicts with Access

I'm having trouble writing a query that will tell me if a given car is booked for a specified date period. My table is called Bookings and has CarID, StartDate and EndDate columns. I want to return a row if the car is booked for the period that the user enters. At the moment I have this query, which I got from the internet and some tinkering:
SELECT *
FROM Bookings
WHERE BookingID NOT IN
(SELECT BookingID
FROM Bookings
WHERE
(StartDate <= user_start_date AND EndDate >= user_start_date) OR
(StartDate <= user_end_date AND EndDate >= user_end_date) OR
(StartDate >= user_start_date AND EndDate <= user_end_date)) AND
(CarID = 7)
Here, I'm using user_start_date as my start date from the user and user_end_date as the end date from the user, and 7 for the car. However, the logic doesn't seem to work. Even when I verify there's absolutely no clashes in the dates it always returns rows.
How can I ammend this query so it works?
Thanks
Assuming that none of the dates can be null, and the start dates are less than the end dates, the following query should list any bookings for car 7 that overlap the given date range:
SELECT *
FROM Bookings
WHERE CarID = 7
AND StartDate < user_end_date
AND EndDate > user_start_date

employee database with varing salary over time

I have the following tables:
PROJECTS - project_id, name
EMPLOYEES - employee_id, name
SALARY - employee_id, date, per_hour
HOURS - log_id, project_id, employee_id, date, num_hours
I need to query how much a project is costing. Problem is that Salary can vary. For example, a person can get a raise.
The SALARY table logs the per_hour charge for an employee. With every change in cost being recorded with its date.
How can I query this information to make sure that the the log from the HOURS table is always matched to the right entry from the SALARY table. Right match being.. depending on the date of the hours log, get the row from the salary table with the highest date before the log's date.
ie.. if the work was performed on Feb 14th. Get the row for this employee from the Salary table with the highest date.. but still before the 14th.
Thank you,
What you need is an end date on SALARY. When a new record is inserted into SALARY for an employee, the previous record with the highest date (or better yet, a current flag set to 'Y' as recommended by cletus) should have its end date column set to the same date as the start date for the new record.
This should work with your current schema but be aware that it may be slow.
SELECT
SUM(h.num_hours * s.per_hour) AS cost
FROM PROJECTS p
INNER JOIN HOURS h
ON p.project_id = h.project_id
INNER JOIN (
SELECT
s1.employee_id,
s1.date AS start_date,
MIN(s2.date) AS end_date
FROM SALARY s1
INNER JOIN SALARY s2
ON s1.employee_id = s2.employee_id
AND s1.date < s2.date
GROUP BY
s1.employee_id,
s1.date) s
ON h.employee_id = s.employee_id
AND h.date >= s.start_date
AND h.date < s.end_date
In the 'Hours' table actually log the value of the salary that you use (don't link it based on ID). This will give you more flexibility in the future.
I have found the easiest way to handle queries spanning dates like this is to store a StartDate and an EndDate, where the EndDate is NULL for the current salary. I use a trigger to make sure there is only ever one NULL value for EndDate, and that there are no overlapping date ranges, or gaps between the ranges. StartDate is made not nullable, since that is never a valid value.
Then your join is pretty simple:
select h.num_hours, s.per_hour
from hours h
inner join salary s on h.employee_id = s.employee_id
and h.date >= s.StartDate and (h.date <= s.EndDate or s.EndDate is null)

MySQL - Reporting using a week to represent all rows with a datestamp in that week

I am trying to build a table of data where each row represents a week (i.e., 09/23-09/30). Each row is built from data from several different rows that have datestamps within that week period. The rest of the columns are subselects that typically give averages of all the data in all the rows in the week period.
Logically, what is the best way to go about this? I've managed to create a query that gives me one row with a startDate and endDate and all the data for the startDate and endDate.
What I need is to have the query return each consequent weeks single row of data, basically giving me the entire report as opposed to one line of the report.
Unfortunately, I can't simply loop through the query in PHP. This has to be in a stored procedure when all is said and done.
Edit:
Here is the SQL I am currently using
BEGIN
if (NOT fromDate) then
SET fromDate = "2007-9-25";
end if;
if (NOT toDate) then
SET toDate = CURDATE();
end if;
SELECT
(SELECT
CONCAT(
MONTH(fromDate),
'/',
DAY(fromDate),
' - ',
MONTH(toDate),
'/',
DAY(toDate)
)
) AS dateRange
,
(SELECT
COUNT(DISTINCT kioskID)
FROM tbl_rpt_kiosksessions
WHERE startDate
BETWEEN fromDate AND toDate
) AS NumberOfStores
,
(SELECT
COUNT(sessionID)
FROM tbl_rpt_kiosksessions
WHERE startDate
BETWEEN fromDate AND toDate
) AS NumberOfSessions
,
(
(
(
(SELECT
COUNT(sessionID)
FROM tbl_rpt_kiosksessions
WHERE startDate
BETWEEN fromDate AND toDate
)
/
(SELECT
COUNT(DISTINCT kioskID)
FROM tbl_rpt_kiosksessions
WHERE startDate
BETWEEN fromDate AND toDate
)
)
/7)
) AS SessionsPerDay
,
(SELECT
(AVG(duration)/60)
FROM tbl_rpt_kiosksessions
WHERE startDate
BETWEEN fromDate AND toDate
) AS AvgSessionLength
FROM
tbl_rpt_kiosksessions
WHERE
startDate
BETWEEN "2010-02-09" AND CURDATE()
GROUP BY DATE_FORMAT(startDate, '%Y-%V');
END
The result of this supposing the following parameters ('2010-02-07','2010-02-14') is:
Image of the record returned
Which is obviously exactly what you'd expect. What I need to figure out is how to get this automated using just a startDate. So, for instance:
startDate = '2010-01-24'
And then getting result sets returned for:
01/24 - 01/30
01/31 - 02/06
02/07 - 02/14
and so on until the endDate is given or is simply CURDATE().
Thoughts?
SELECT data columns / aggregate functions FROM table GROUP BY DATE_FORMAT(date_column, '%Y-%V')
(%V assumes weeks start on Sunday - switch to %v for Monday)