Sql SELECT for personnel available in a specific time period - sql

I have 3 tables. First one is a list of personnel:
Table Personnel
Id_personnel Name
1 John
2 Alice
3 Tom
4 Charles
5 Ben
Second is a table with medical leave:
Table Medical
Id_personnel Start_date End_date
3 2012-08-02 2012-08-05
2 2012-08-02 2012-08-15
4 2012-10-04 2012-10-06
2 2012-10-02 2012-10-15
2 2012-09-20 2012-09-21
Third is a table with holiday leave:
Table Holiday
Id_personnel Start_date End_date
3 2012-08-02 2012-08-05
2 2012-02-02 2012-02-15
5 2012-10-01 2012-10-05
I have two event dates: Symposium_start_date and a Symposium_end_date (as variables) and I would like to select all Personnel.Id_personnel and Personnel.Name available for the symposium (not in medical leave or on holiday).
In my example if Symposium_start_date = 2012-10-02 and Symposium_end_date = 2012-10-06 the result must be:
Id_personnel Name
1 John
3 Tom
(as you can see Alice and Charles are on medical leave and Ben on holiday)
Thank you!

For a MS SQL server.
declare #start date = '2012-10-02', #end date = '2012-10-10'
select personnel.*
from personnel
left join holiday on personnel.Id_personnel = holiday.Id_personnel
and holiday.start_date<=#end
and holiday.end_date>=#start
left join medical on personnel.Id_personnel= medical.Id_personnel
and medical.start_date<=#end
and medical.end_date>=#start
where holiday.Id_personnel is null
and medical.Id_personnel is null

assuming MS-SQL, similar to others, but have shown tables unioned together, and subquery that shows all those who conflict with the symposium dates - I think this is easier to write first - and then selecting all those people who are NOT conflicting. Regards!
declare #Symposium_start_date date = '2012-10-02'
declare #Symposium_end_date date = '2012-10-06'
select * from Personnel P where p.Id_personnel not in (
select Id_personnel from (
select m.Id_personnel, m.Start_date, m.End_date
from Medical M
union
select h.Id_personnel, h.Start_date, h.End_date
from Holiday H
) as Leave
where (Start_date between #Symposium_start_date and #Symposium_end_date)
or (End_date between #Symposium_start_date and #Symposium_end_date)
or (Start_date <= #Symposium_start_date and End_date >= #Symposium_end_date)
)

this is an example with the Medical table only. You can easily add the Holiday
declare #Symposium_start_date datetime
declare #Symposium_end_date datetime
set #Symposium_start_date = '2012-08-01'
set #Symposium_end_date = '2012-08-04'
select *
from personel p left join medical m on p.Id_personel = m.Id_personel
where (#Symposium_start_date > m.end_date) or (#Symposium_end_date<m.start_date)

Related

Count active merchants according to contract creation date and termination date for each day from 2017

So I would like to count my active partners (merchants) for each day from 2017-01-01
I have a postgresql datawarehouse where
I have a source table called sources like this:
merchantid
contract_date
termination_date
1
2018-05-28
2021-05-28
2
2018-05-27
2022-05-27
3
2018-16-14
NULL
4
2020-11-14
NULL
5
2021-03-15
NULL
6
2022-01-04
NULL
And I have a goal table called historical_active_merchants table like this:
date
num_of_merchants
...
...
2021-05-26
2021-05-27
2021-05-27
2021-05-27
2021-05-27
2021-05-27
...
...
...
... are days before and after from 2017-01-01 until now
My logic how it would be nice to work:
UPDATE historical_active_merchants SET num_of_merchants=num_of_merchants+1
WHERE (sources.contract_date <= historical_active_merchants.date
AND sources.termination_date > historical_active_merchants.date)
OR (sources.contract_date <= historical_active_merchants.date
AND sources.termination_date is null)
Is it possible without loops?
Or is there a solution by using loop?
I just can't list here all the attepmts I've tried already...
I appreciate any tips and solutions and thanks in advance!
You can update historical_active_merchants based on a select that counts the merchants.
update historical_active_merchants H
set num_of_merchants = count_merchants
from (
select H.date, count(S.merchantid) as count_merchants
from historical_active_merchants H
left join sources S on H.date >= S.contract_date
and (S.termination_date is null or H.date <= S.termination_date)
group by H.date
) X
where H.date = X.date;
(the subquery is needed because of the group by)

SQL derived attribute

I want to make the Room_Status in Table 1 (ROOM) table into a derived attribute base on the check_in and check_out date Table 2 (Booking Records) table, but I don't know if it is possible to determine the room status dynamically based on the check_in/check_out date in table 2 , eg. The room with room_no 103 suppose to be unavailable for day 19/02/2020 to 20/02/2020 because its already booked by someone else , so the room status will be displayed as unavailable or N, after date 20/02/2020 the room will be available again.
Another extra thing is that I want to calculate the days available for each room based on the table 2 check_in and check_out date eg. room 103 will be available for only 1 day if it is booked on 19/02/2020 to 20/02/2020 after one day which is 22/02/2020 the room is booked by another customer, how should I calculate the days available...
Table 1 (ROOM)
ROOM_NO ROOM_STATUS ('Y' represent 'Available' , 'N' represent 'Unavailable')
======= ============
1 Y
2 Y
3 Y
4 Y
5 Y
6 Y
7 Y
8 Y
9 Y
10 Y
more rooms.....
Table 2 (Booking Records)
BOOKING_ID CHECK_IN CHECK_OUT SPECIAL_REQ CANCEL_REASON DATE_BOOK ROOM_NO GUEST
========== ======== ========= =========== ============= ========= ======= =====
1 19/02/2020 20/02/2020 Prepare hot bath tub 17/02/2020 103 980315070652
when check in.
2 20/05/2020 27/05/2020 Prepare scented 10/05/2020 10 C00001549
candle and meal when
check in
3 21/05/2020 23/05/2020 Prepare latest news 10/05/2020 9 C00001894
paper in room
4 20/05/2020 24/05/2020 Prepare hot bath tub 17/05/2020 124 980315070652
when check in.
Not sure I'm following, something like this? Strictness of the inequality (<,<=) will depend on how you want to define available on a given day.
SELECT DISTINCT
Room_No,
CASE WHEN EXISTS
( SELECT 1
FROM Booking_Records BR2
WHERE BR.room_no = BR2.room_no
AND CURRENT_DATE >= BR2.Check_In
AND CURRENT_DATE < BR2.Check_Out
) THEN 'N'
ELSE 'Y'
END AS Currently_Available
FROM Booking_Records BR
This will get the rooms from the booking_records table that are available on 2020-05-22:
SELECT room_no,
CASE COUNT(
CASE
WHEN DATE '2020-05-22' BETWEEN CHECK_IN AND CHECK_OUT
AND cancel_reason IS NULL
THEN 1
END
)
WHEN 0
THEN 'Y'
ELSE 'N'
END AS room_status_20200522
FROM booking_records
GROUP BY room_no
Which, for your sample data:
CREATE TABLE booking_records ( BOOKING_ID, CHECK_IN, CHECK_OUT, CANCEL_REASON, ROOM_NO ) AS
SELECT 1, DATE '2020-02-19', DATE '2020-02-20', CAST( NULL AS VARCHAR2(50) ), 103 FROM DUAL UNION ALL
SELECT 2, DATE '2020-05-20', DATE '2020-05-27', NULL, 10 FROM DUAL UNION ALL
SELECT 3, DATE '2020-05-21', DATE '2020-05-23', NULL, 9 FROM DUAL UNION ALL
SELECT 4, DATE '2020-05-20', DATE '2020-05-24', NULL, 124 FROM DUAL;
Outputs:
ROOM_NO | ROOM_STATUS_20200522
------: | :-------------------
9 | N
103 | Y
10 | N
124 | N
db<>fiddle here
So, You need to fetch room status and number of day availability after room is free.
I am considering that booking_records table can contain more than one reservation for the same room_no.
Following query will give you desired details as of sysdate.
Select r.room_no,
Max(Case when b.bookin_id is not null then'N' else 'Y' end) as booking_status,
Min(bn.check_in - coalesce(b.check_out,sysdate)) as available_days
From rooms r
Left Join booking_records b
On b.room_no = r.room_no
And sysdate between b.check_in and b.check_out
Left join booking_records bn
On bn.room_no = r.room_no
And bn.check_in > sysdate
Group by r.room_no

Find missing rows between three related tables

I have three tables:
Person
person_id
-------------
10001
10002
10003
10004
Dates
date_type date
-------------- -----------------------
PUBLIC_HOLIDAY 2020-04-10 00:00:00.000
PUBLIC_HOLIDAY 2020-04-13 00:00:00.000
Absence
person_id date absence_type
--------- ----------------------- ------------
10001 2020-04-10 00:00:00.000 HOLIDAY
10001 2020-04-13 00:00:00.000 HOLIDAY
10002 2020-04-10 00:00:00.000 HOLIDAY
10003 2020-04-13 00:00:00.000 HOLIDAY
I need to find all of the person_id's in the Person table and the date's from the Dates table who have not booked any absence matching the following criteria:
Dates.date_type = 'PUBLIC_HOLIDAY'
Absence.absence_type = 'HOLIDAY'
Basically, I need to find the people and the dates which are public holidays they have not booked an absence for as holiday.
You can try this below logic-
DEMO HERE
SELECT Person.person_id,Dates.dat,ISNULL(Absence.dat, 'Not Bokked')
FROM Dates
CROSS JOIN Person
LEFT JOIN Absence ON Person.person_id = Absence.person_id AND Dates.dat = Absence.dat
WHERE Dates.date_type = 'PUBLIC_HOLIDAY'
If you wants only information with not booked, just simply add below line to the script-
AND Absence.dat IS NULL
I think that you want a cross join to generate all combinations of persons and dates, and then not exists to filter on those that do not exist in the absence table:
select p.*, d.*
from person p
cross join dates d
where
d.date_type = 'PUBLIC_HOLIDAY'
and not exists (
select 1
from absence a
where a.person_id = p.person_id and a.date = d.date and a.absence_type = 'HOLIDAY'
)
Try:
select distinct person_id from absence a
where absence_type = 'HOLIDAY'
and not exists (select 1 from dates
where date = a.date
and date_type = 'PUBLIC_HOLIDAY')
union all
select person_id from person p
where not exists ( select 1 from absence
where p.person_id = person_id)
If you want to have them with dates, use below query:
select person_id, date from absence a
where absence_type = 'HOLIDAY'
and not exists (select 1 from dates
where date = a.date
and date_type = 'PUBLIC_HOLIDAY')
union all
-- in person table we don;t have any dates
select person_id, null from person p
where not exists ( select 1 from absence
where p.person_id = person_id)
you can use below query. I have tested this in SQL Server 2014.
CREATE TABLE #Person(person_id INT)
INSERT INTO #person
values
(10001),
(10002),
(10003),
(10004);
CREATE TABLE #Dates (date_Type VARCHAR(50), [datevalue] datetime)
INSERT INTO #Dates
VALUES
('PUBLIC_HOLIDAY','2020-04-10 00:00:00.000'),
('PUBLIC_HOLIDAY','2020-04-13 00:00:00.000');
CREATE TABLE #Absence (person_id int, datevalue datetime, absence_type VARCHAR(50))
INSERT INTO #Absence
VALUES
(10001,'2020-04-10 00:00:00.000','HOLIDAY'),
(10001,'2020-04-13 00:00:00.000','HOLIDAY'),
(10002,'2020-04-10 00:00:00.000','HOLIDAY'),
(10003,'2020-04-13 00:00:00.000','HOLIDAY');
SELECT p.person_id, od.datevalue
FROM #Person AS p
CROSS JOIN (SELECT * FROM #Dates WHERE date_type ='PUBLIC_HOLIDAY') AS od
WHERE NOT EXISTS
(
SELECT 1 FROM
#Absence AS a
INNER JOIN #Dates AS d
ON a.datevalue = d.datevalue
WHERE a.absence_type = 'Holiday' AND d.date_type = 'PUBLIC_HOLIDAY'
AND a.person_id = p.person_id and d.datevalue = od.datevalue)
Below is the resultset:
+-----------+-------------------------+
| person_id | datevalue |
+-----------+-------------------------+
| 10003 | 2020-04-10 00:00:00.000 |
| 10004 | 2020-04-10 00:00:00.000 |
| 10002 | 2020-04-13 00:00:00.000 |
| 10004 | 2020-04-13 00:00:00.000 |
+-----------+-------------------------+

How to get columns from second table only if data exists otherwise should return null?

I am struggling with SQL Joins concept and am facing problem when I am trying to get student attendance record. There are 3 tables that have to be used.
attendance a - has all student attendance
st_holiday b, - student specific holiday public list
hol_list c - all holiday list including weekend
There are 2 questions:
1. I need data that gives me in_time, out_time and holiday_type to me. Student can also attend class on his holiday date(can be public holiday or weekend).
I tried below query which gives me only holiday attended dates.
select a.student_id, a.in_time, a.out_time, b.holiday_type
from attendance a, st_holiday b, hol_list c
where a.st_id = b.st_id
and b.holiday = c.id
and a.date = c.hol_date
I have also tried using left outer join st_holiday on a.st_id = b.st_id and left outer join holiday_type on a.date = c.hol_date
But it gives me all data and for each data holiday_type shows as Holiday/weekend, etc.
2. How to parameterize by date. I need to provide the data as sql script with date range parameterized. How to do the same in Sql Server. I tried using
DECLARE from_date='2015-04-01 00:00:00.000'
DECLARE to_date='2015-04-01 00:00:00.000'
SELECT * FROM TABLE
WHERE ....
AND [PI].Date BETWEEN ISNULL(#FromDate, [PI].Date) AND ISNULL(#ToDate, [PI].Date)
I used below link for reference. sql server optional parameters: syntax for between clause
Any help will be appreciated.
Update : Table Structure.
attendance a - primary Key ID, st_id shared with st_holiday table
st_holiday b, - pk is ID, holiday shared with hol_list table
hol_list c - hol_date can be used with date of attendance table.
Expected output:
St_id IN_TIME OUT_TIME Hol_type
1234 2015-08-07 08:00:00.000 2015-08-07 17:00:00.000 null
1234 2015-08-08 08:00:00.000 2015-08-08 08:00:00.000 Weekend
Table structure : st_id in attendance and st_holiday table are not unique. The value will be repeated. For eg. eah st_id in st_holiday will have 20 holidays for very year i.e. st_id is repeated 20 times. In attendance table st_id will depend on no. of times student comes in and goes out of classroom.
attendance
-------------
st_id in_time out_time time_in_class
3370 2009-10-8 11:54:0.0 2009-10-8 18:1:0.0 6.11666666666667
4209 0 0 0
4225 0 0 0
3779 2009-10-8 14:27:0.0 2009-10-9 0:5:0.0 9.63333333333333
hol_list
-------------
id hol_date type desc holiday_type
229 2007-04-06 00:00:00.000 1 Good Friday Holiday
231 2007-05-01 00:00:00.000 1 International Labor Day Holiday
233 2007-07-04 00:00:00.000 1 Independence Day Holiday
234 2007-07-07 00:00:00.000 1 Weekend Weekend
st_holiday
-------------
st_id holiday holiday_type
9201 39965 Holiday
9201 39961 Holiday
9201 39951 Holiday
9201 39942 Holiday
9201 39935 Weekend
9201 39927 Holiday
Based on your sample query and explanation. For your first question, kindly give this a try:
select a.student_id, a.in_time, a.out_time, b.holiday_type
from attendance a
left join st_holiday b on a.st_id = b.st_id
inner join hol_list c on a.date = c.hol_date

insert duplicate rows in temp table

i'm a new to sql & forum - need help on how to insert duplicate rows in temp table. Would like to create a view as result
View - Employee:
Name Empid Status Manager Dept StartDate EndDate
AAA 111 Active A111 Cashier 2015-01-01 2015-05-01
AAA 111 Active A222 Sales 2015-05-01 NULL
I don't know how to write a function, but do have a DATE table.
Date Table: (365 days) goes up to 2018
Date Fiscal_Wk Fiscal_Mon Fiscal_Yr
2015-01-01 1 1 2015
Result inquiry
How do i duplicate rows for each record from Employee base on each of the start date for entire calendar year.
Result:
Name Empid Status Manager Dept Date FW FM FY
AAA 111 Active A111 Cashier 2015-01-01 1 1 2015
AAA 111 Active A111 Cashier 2015-01-02 1 1 2015
******so on!!!!!!
AAA 111 Active A222 Sales 2015-05-01 18 5 2015
AAA 111 Active A222 Sales 2015-05-02 18 5 2015
******so on!!!!!!
Thanks in advance,
Quinn
Select * from Employee cross join Calendar.
This will essentially join every record in calendar to every record in Employee.
so, if there are 2 records in Employee and 10 in calendar, you'll end up with 20 total, 10 for each.
What you are looking for is a join operation. However, the condition for the join is not equality, because you want all rows that match between two values.
The basic idea is:
select e.*, c.date
from employee e join
calendar c
on e.startdate >= c.date and
(e.enddate is null or c.date <= e.enddate);
modified query - this yields result of previous & most recent records
select e.*, c.date, c.FW, c.FM, c.FY
from employee e
join calendar c
on e.startdate <= c.date and
ISNULL(e.enddate,GETDATE()) > c.date