I have a dataset with a column FromDate and I am trying to create another column ToDate based on the FromDate from the previous record.
The corresponding ToDate for the latest FromDate will default to '9999-12-31'. Is there anyway I can do this using SQL?
Current Sample Dataset
ID| FromDate
1 | 2022-02-08
1 | 2022-01-05
1 | 2022-01-02
2 | 2022-04-03
2 | 2022-01-07
2 | 2022-12-04
Expected Output
ID| FromDate | ToDate
1 | 2022-02-08 | 9999-12-31
1 | 2022-01-05 | 2022-02-07
1 | 2022-01-02 | 2022-01-04
2 | 2022-04-03 | 9999-12-31
2 | 2022-01-07 | 2022-04-02
2 | 2021-12-04 | 2022-01-06
Using Lead/Lag you could do something like:
SELECT ID, FromDate,
COALESCE(LEAD(DATEADD(DAY, -1, FromDate)) OVER (PARTITION BY ID ORDER BY FromDate), '99991231') as ToDate
FROM yourtable;
Related
I need to separate the "dep" column into 2 different columns one being "recorded" the other being "unrecorded". the "unrecorded" column will contain the sum of time for entries where "dep" is blank or null for that day. The "recorded" column needs to display the sum of time for that day where the "dep" column is not null or blank.
So far this is what I have
SELECT Cast(Start_Time AS DATE) AS Date, dep,
sum(time) as "Total Time"
FROM A6K_Events
Group By Cast(Start_Time AS DATE), dep
and it yields this
+------------+--------------+------------+
| Date | Dep | Total Time |
+------------+--------------+------------+
| 2018-06-29 | Null | 3544 |
+------------+--------------+------------+
| 2018-06-29 | Other | 268 |
+------------+--------------+------------+
| 2018-06-29 | Training | 471 |
+------------+--------------+------------+
| 2018-06-29 | Change Point | 371 |
+------------+--------------+------------+
| 2018-06-28 | Null | 4519 |
+------------+--------------+------------+
| 2018-06-28 | Training | 1324 |
+------------+--------------+------------+
| 2018-06-28 | | 50 |
+------------+--------------+------------+
This is what I would like the end result to be
+------------+----------+------------+
| Date | Recorded | Unrecorded |
+------------+----------+------------+
| 2018-06-29 | 1110 | 3544 |
+------------+----------+------------+
| 2018-06-28 | 1324 | 4569 |
+------------+----------+------------+
Any suggestions or help would be appreciated. I cannot figure out how to pivot and filter out null and blank values into one column while the other filled values into another column.
Thank you.
Pivot is not required, we can fetch the data using CASE statement
SELECT start_time as Date, sum(case when dep is not NULL or dep <> '' then time end) as "Recorded", sum(case when dep is NULL or dep = '' then time end) as "Unrecorded"
FROM A6K_Events
Group By start_time order by 1 desc
From my table, I want to select for each project ID the ID with the latest deploymentDate and if there are two identical latest deployment dates for the same project ID, select the ID with the latest submittedOn datetime. So if my table looks like this:
id | projectId | deploymentDate | submittedOn |
1 | 1 | 2017-01-02 | 2017-01-02 13:00:00 |
2 | 1 | 2017-01-04 | 2017-01-04 11:00:00 |
3 | 2 | 2017-01-06 | 2017-01-06 17:00:00 |
4 | 2 | 2017-01-06 | 2017-01-01 12:00:00 |
5 | 3 | 2017-01-02 | 2017-01-02 13:30:00 |
6 | 3 | 2017-01-02 | 2017-01-05 15:00:00 |
7 | 3 | 2017-01-02 | 2017-01-04 10:00:00 |
The desired rows are:
id | projectId | deploymentDate | submittedOn |
2 | 1 | 2017-01-04 | 2017-01-04 11:00:00 |
3 | 2 | 2017-01-06 | 2017-01-06 17:00:00 |
6 | 3 | 2017-01-02 | 2017-01-05 15:00:00 |
You can try the below. Adjust the sorting in the row_number as needed.
select
a.id,
a.projectid,
a.deploymentdate,
a.submittedOn
from project a
inner join
(select
a.id,
row_number() over (partition by projectid order by deploymentdate desc, submittedOn desc, id) as rid
from project
) as b
on b.id = a.id
and b.rid = 1
This would work:
select t.id, latest.*
from tab t join (
select projectid, max(deploymentdate) deploymentdate, max(submittedon) submittedon
from tab
group by projectid
) latest on t.projectid = latest.projectid and t.deploymentdate = latest.deploymentdate and t.submittedon = latest.submittedon
I found the latest based on the project id and then, joined with the source table to find the corresponding id.
I want to 'clean' a dataset and declare a new variable, then input a date based on rank.
My dataset looks like this:
+-----+--------------+------------+-------+
| ID | Start_date | End_date | Rank |
+-----+--------------+------------+-------+
| a | May '16 | May '16 | 5 |
| a | Jun '16 | Jul '16 | 4 |
| a | Jul '16 | Aug '16 | 3 |
| a | Aug '16 | NULL '16 | 2 |
| a | Sept '16 | NULL '16 | 1 |
+-----+--------------+------------+-------+
I basically want to input the start date of rank 1 into the end date of rank 2 or say input start 5 into end 6 (always -1).
Have written the following to select into a tempory table and rank based on id and date:
SELECT
[Start_Date] as 'start'
,[End_Date] as 'end'
,[Code] as 'code'
,[ID] as 'id'
,rank() over (partition by [id] order by [Start_Date]) as 'rank'
INTO #1
FROM [Table]
ORDER BY [id]
Its the following part that doesn't work ...
DECLARE new_end
BEGIN select [#1].[start] into new_end FROM [#1]
WHERE (
([#1].[rank] = 1)
AND ([#1].[end] IS NULL)
)
Assuming you already have your dataset as provided in your question, this is just a simple self join, no?
declare #t table(ID nvarchar(1), Start_date date, End_date date, [Rank] int);
insert into #t values ('a','20170501','20170501',5),('a','20170601','20170701',4),('a','20170701','20170801',3),('a','20170801',NULL,2),('a','20170901',NULL,1);
select t1.ID
,t1.Start_date
,isnull(t1.End_date,t2.Start_date) as End_date
-- If you *always* want to overwrite the End_Date use this instead:
-- ,t2.Start_date as End_date
,t1.[Rank]
from #t t1
left join #t t2
on(t1.[Rank] = t2.[Rank]+1);
Output:
+----+------------+------------+------+
| ID | Start_date | End_date | Rank |
+----+------------+------------+------+
| a | 2017-05-01 | 2017-05-01 | 5 |
| a | 2017-06-01 | 2017-07-01 | 4 |
| a | 2017-07-01 | 2017-08-01 | 3 |
| a | 2017-08-01 | 2017-09-01 | 2 |
| a | 2017-09-01 | NULL | 1 |
+----+------------+------------+------+
First of all please correct me if my title are not specific/clear enough.
I have use the following code to generate the start dates and end dates :
DECLARE #start_date date, #end_date date;
SET #start_date = '2016-07-01';
with dates as
(
select
#start_date AS startDate,
DATEADD(DAY, 6, #start_date) AS endDate
union all
select
DATEADD(DAY, 7, startDate) AS startDate,
DATEADD(DAY, 7, endDate) AS endDate
from
dates
where
startDate < '2017-03-31'
)
select * from dates
Below is part of the output from above query :
+------------+------------+
| startDate | endDate |
+------------+------------+
| 2016-07-01 | 2016-07-07 |
| 2016-07-08 | 2016-07-14 |
| 2016-07-15 | 2016-07-21 |
| 2016-07-22 | 2016-07-28 |
| 2016-07-29 | 2016-08-04 |
+------------+------------+
Now I have another table named sales, which have 3 columns sales_id,sales_date and sales_amount as below :
+----------+------------+--------------+
| sales_ID | sales_date | sales_amount |
+----------+------------+--------------+
| 1 | 2016-07-04 | 10 |
| 2 | 2016-07-06 | 20 |
| 3 | 2016-07-13 | 30 |
| 4 | 2016-07-19 | 15 |
| 5 | 2016-07-21 | 20 |
| 6 | 2016-07-25 | 25 |
| 7 | 2016-07-26 | 40 |
| 8 | 2016-07-29 | 20 |
| 9 | 2016-08-01 | 30 |
| 10 | 2016-08-02 | 30 |
| 11 | 2016-08-03 | 40 |
+----------+------------+--------------+
How can I create the query to show the total sales amount of each week (which is between each startDate and endDate from the first table)? I suppose I will need to use a recursive query with WHERE clause to check if the dates are in between startDate and endDate but I cant find a working example.
Here are my expected result (the startDate and endDate are the records from the first table) :
+------------+------------+--------------+
| startDate | endDate | sales_amount |
+------------+------------+--------------+
| 2016-07-01 | 2016-07-07 | 30 |
| 2016-07-08 | 2016-07-14 | 30 |
| 2016-07-15 | 2016-07-21 | 35 |
| 2016-07-22 | 2016-07-28 | 65 |
| 2016-07-29 | 2016-08-04 | 120 |
+------------+------------+--------------+
Thank you!
Your final Select (after the cte) should be something like this
Select D.*
,Sales_Amount = sum(Sales)
From dates D
Join Sales S on (S.sales_date between D.startDate and D.endDate)
Group By D.startDate,D.endDate
Order By D.startDate
EDIT: You could use a Left Join if you want to see missing dates from
Sales
I have a dataset (DATASET1) that lists all employees with their Dept IDs, the date they started and the date they were terminated.
I'd like my query to return a dataset in which every row represents a day for each employee stayed employed, with number of days worked (Start-to-Date).
How do I this query? Thanks for your help, in advance.
DATASET1
DeptID EmployeeID StartDate EndDate
--------------------------------------------
001 123 20100101 20120101
001 124 20100505 20130101
DATASET2
DeptID EmployeeID Date #ofDaysWorked
--------------------------------------------
001 123 20100101 1
001 123 20100102 2
001 123 20100103 3
001 123 20100104 4
.... .... ........ ...
EIDT: My goal is to build a fact table which would be used to derive measures in SSAS. The measure I am building is 'average length of employment'. The measure will be deployed in a dashboard and the users will have the ability to select a calendar period and drill-down into month, week and days. That's why I need to start with such a large dataset. Maybe I can accomplish this goal by using MDX queries but how?
You can use a recursive CTE to perform this:
;with data (deptid, employeeid, inc_date, enddate) as
(
select deptid, employeeid, startdate, enddate
from yourtable
union all
select deptid, employeeid,
dateadd(d, 1, inc_date),
enddate
from data
where dateadd(d, 1, inc_date) <= enddate
)
select deptid,
employeeid,
inc_date,
rn NoOfDaysWorked
from
(
select deptid, employeeid,
inc_date,
row_number() over(partition by deptid, employeeid
order by inc_date) rn
from data
) src
OPTION(MAXRECURSION 0)
See SQL Fiddle with Demo
The result is similar to this:
| DEPTID | EMPLOYEEID | DATE | NOOFDAYSWORKED |
-----------------------------------------------------
| 1 | 123 | 2010-01-01 | 1 |
| 1 | 123 | 2010-01-02 | 2 |
| 1 | 123 | 2010-01-03 | 3 |
| 1 | 123 | 2010-01-04 | 4 |
| 1 | 123 | 2010-01-05 | 5 |
| 1 | 123 | 2010-01-06 | 6 |
| 1 | 123 | 2010-01-07 | 7 |
| 1 | 123 | 2010-01-08 | 8 |
| 1 | 123 | 2010-01-09 | 9 |
| 1 | 123 | 2010-01-10 | 10 |
| 1 | 123 | 2010-01-11 | 11 |
| 1 | 123 | 2010-01-12 | 12 |
SELECT DeptID, EmployeeID, Date, DATEDIFF(DAY, StartDate, '3/1/2011') AS ofDaysWorked
FROM DATASET1
See if that worked!