SQL - Group vacations in a table based on a holidays - sql

Here is the sample data from the employee vacation table.
Emp_id Vacation_Start_Date Vacation_End_Date Public_Hday
1234 06/01/2022 06/07/2022 null
1234 06/08/2022 06/14/2022 null
1234 06/15/2022 06/19/2022 06/17/2022
1234 06/20/2022 06/23/2022 null
1234 06/24/2022 06/28/2022 null
1234 06/29/2022 07/02/2022 06/30/2022
1234 07/03/2022 07/07/2022 null
1234 07/08/2022 07/12/2022 null
1234 07/13/2022 07/17/2022 07/15/2022
1234 07/18/2022 07/22/2022 null
I want to group these vacations based on the public holidays in between (Assuming that all the vacations are consecutive). Here is the output that I am trying to get.
Emp_id Vacation_Start_Date Vacation_End_Date Public_Hday Group
1234 06/01/2022 06/07/2022 null 0
1234 06/08/2022 06/14/2022 null 0
1234 06/15/2022 06/19/2022 06/17/2022 1
1234 06/20/2022 06/23/2022 null 1
1234 06/24/2022 06/28/2022 null 1
1234 06/29/2022 07/02/2022 06/30/2022 2
1234 07/03/2022 07/07/2022 null 2
1234 07/08/2022 07/12/2022 null 2
1234 07/13/2022 07/17/2022 07/15/2022 3
1234 07/18/2022 07/22/2022 null 3
Here is the code that I tried
Select *, dense_rank() over (partition by Emp_id order by Public_Hday) - 1 AS Group from Emp_Vacation.
But, it gave the expected group values only to the vacations where the Public_Hday is not null. How do I get the group values to the other vacations.

You can use a conditional sum() over()
Select *
,Grp = sum( case when [Public_Hday] is null then 0 else 1 end ) over (partition by [Emp_id] order by [Vacation_Start_Date])
from YourTable
Results

Related

Update SQL table date based on column in another table

I have a table like this:
ID
start_date
end_date
1
09/01/2022
1
09/04/2022
2
09/01/2022
I have another reference table like this:
ID
date
owner
1
09/01/2022
null
1
09/02/2022
null
1
09/03/2022
Joe
1
09/04/2022
null
1
09/05/2022
Jack
2
09/01/2022
null
2
09/02/2022
John
2
09/03/2022
John
2
09/04/2022
John
For every ID and start_date in the first table, I need find rows in the reference table that occur after start_date, and have non-null owner. Then I need to update this date value in end_date of first table.
Below is the output that I want:
ID
date
end_date
1
09/01/2022
09/03/2022
1
09/04/2022
09/05/2022
2
09/01/2022
09/02/2022

Removing duplicates rows by max date on ordered table

I have the table Example Table with the following data
Example Table
ID
DATE
NAME
9
2021-04-13 21:39:00.569000
ABC
8
2020-12-17 16:49:17.903000
ABC
7
2020-12-16 16:49:17.903000
ABC
6
2020-06-09 09:55:52.005000
WER
5
2020-06-09 09:55:52.004000
WER
4
2020-06-08 09:48:43.318000
YTG
3
2020-06-05 14:51:42.860000
YTG
2
2020-04-28 13:58:30.972000
YTG
1
2020-04-25 13:58:30.972000
ABC
And I want to get for every distinct NAME in the table it's has max date until found a diffrent NAME. So the result set must be as the following
Expected Output
ID
DATE
NAME
9
2021-04-13 21:39:00.569000
ABC
6
2020-06-09 09:55:52.005000
WER
4
2020-06-08 09:48:43.318000
YTG
1
2020-04-25 13:58:30.972000
ABC
I tried sql query as below and got no result.
select NAME
from
(
select NAME, max(DATE) - min(DATE) as diff
from Example_Table
group by NAME
) ex
order by diff desc;
Use lead():
select t.*
from (select t.*,
lead(name) over (order by date) as next_name
from t
) t
where next_name is null or next_name <> name;

Dense Rank Skip Null Values Partition by Multiple

I have a table that looks like below:
Date User Product
11/15/2019 123 NULL
11/21/2019 123 A
11/21/2019 123 A
11/23/2019 123 B
I want to run a dense_rank function that will skip the null values.
Below is what I currently have:
CASE WHEN PRODUCT IS NOT NULL
THEN DENSE_RANK()
OVER (PARTITION BY USER ORDER BY DATE ASC)
ELSE 1
END DENSE_RANK_OUTPUT
My current output:
Date User Product DENSE_RANK_OUTPUT
11/15/2019 123 NULL 1
11/21/2019 123 A 2
11/21/2019 123 A 2
11/23/2019 123 B 3
My desired output is:
Date User Product DESIRED_OUTPUT
11/15/2019 123 NULL 1
11/21/2019 123 A 1
11/21/2019 123 A 1
11/23/2019 123 B 2
You are close. Just use another key in the partition by:
(CASE WHEN PRODUCT IS NOT NULL
THEN DENSE_RANK() OVER (PARTITION BY USER, (PRODUCT IS NOT NULL) ORDER BY DATE ASC)
ELSE 1
END) as DENSE_RANK_OUTPUT

SQL Updating two records

I am trying to update two employee's data. Let say one employee's id is 1234 and the other employee's id is 5678. Each employee has different services.
This is my table for reference
serv_id emp_id serv_name status
1 1234 computer1 A
5 1234 computer2 A
10 1234 computer3 A
37 1234 computer4 A
5 5678 computer2 A
11 5678 projector1 A
12 5678 projector2 A
30 5678 projector3 A
37 5678 computer4 A
35 5678 projector4 A
In the table above, we have 2 employees with 10 records and each employee has 5 services. What I want to do right now is to merge these two employee's services into one employee (1234) because employee 5678 is fired. However, serv_id with '5' or '37' does not need to be updated in employee 1234.
Here is my expected result. Let say A is active and I is inactive. Any suggestion on how to do it?
serv_id (pk) emp_id (fk) serv_name status
1 1234 computer1 A
5 (no update) 1234 computer2 A
10 1234 computer3 A
11 1234 projector1 A
12 1234 projector2 A
30 1234 projector3 A
35 1234 projector4 A
37 (no update) 1234 computer4 A
11 5678 projector1 I
37 5678 computer4 I
5 5678 computer2 I
11 5678 projector1 I
12 5678 projector2 I
30 5678 projector3 I
37 5678 computer4 I
35 5678 projector4 I
Try this
declare #tb as Table (serv_id int, emp_id int, serv_name nvarchar(20),status nvarchar(5))
insert into #tb
select 1 ,1234,'computer1','A' union
select 5 ,1234,'computer2','A' union
select 10,1234,'computer3','A' union
select 37,1234,'computer4','A' union
select 5 ,5678,'computer2','A' union
select 11,5678,'projector1','A' union
select 12,5678,'projector2','A' union
select 30,5678,'projector3','A' union
select 37,5678,'computer4','A' union
select 35,5678,'projector4','A'
update #tb set status ='I' where emp_id = 5678
insert into #tb select serv_id,1234,serv_name,'A' from #tb where emp_id=5678 and serv_id not in (select serv_id from #tb where emp_id=1234)
select * from #tb order by emp_id,serv_id
UPDATE t1
SET t1.status='I'
FROM my_table t1
LEFT OUTER JOIN my_table t2 ON t2.serv_name=t1.serv_name AND t2.emp_id=1234
WHERE t1.emp_id=5678
AND t2.serv_id IS NULL
We can join the table to itself by serv_name and emp_id to find common serv_names and then update only the records which have no same values for the emp_id=1234

SQL Sequence increasing/resetting based on crtieria

I'm trying to write a query in SQL but have hit a brick wall.
My results table looks similar to the below:
Category Date
1234 15/07/2014
1234 17/07/2014
1234 29/07/2014
1234 31/07/2014
1234 02/08/2014
1234 04/08/2014
1234 06/08/2014
1211 17/07/2014
1211 06/08/2014
1211 08/08/2014
I'm trying to create a sequence which resets when the difference in dates is greater than 2 aswell as unique to the category as follows:
Category Date Sequence
1234 15/07/2014 1
1234 17/07/2014 2
1234 29/07/2014 1
1234 31/07/2014 2
1234 02/08/2014 3
1234 04/08/2014 4
1234 06/08/2014 5
1211 17/07/2014 1
1211 06/08/2014 1
1211 08/08/2014 2
This can be accomplished using the CONDITIONAL_TRUE_EVENT function. Thanks to sKwa & scutter for the help!
SELECT Category,
Date,
RANK()
OVER (
PARTITION BY Category, seq
ORDER BY Date)
FROM (SELECT Category,
Date,
CONDITIONAL_TRUE_EVENT(DATEDIFF(day, prev_Date, Date) > 2)
OVER (
PARTITION BY Category
ORDER BY Date) AS seq
FROM (SELECT *,
LAG(Date, 1)
OVER (
PARTITION BY Category
ORDER BY Date) prev_Date
FROM test) q) q2
ORDER BY Category,
Date;