Hi I have a SQL question, I'm trying to get end of month records for each person within a certain date range. Essentially I want this record to be tracking historically (years worth of data) using some sort of End of Month record if their start and end dates fall within the last day of each month. So the data currently looks like this (using just 2022 for simplicity)..
Name
StartDate
EndDate
John Smith
2022-01-15
2022-04-10
Jane Doe
2022-01-18
2022-03-05
Rob Johnson
2022-03-07
2022-07-18
And what I'm looking for is something like this
Name
StartDate
EndDate
EndMonth
John Smith
2022-01-15
2022-04-10
2022-01-31
Jane Doe
2022-01-18
2022-03-05
2022-01-31
John Smith
2022-01-15
2022-04-10
2022-02-28
Jane Doe
2022-01-18
2022-03-05
2022-02-28
John Smith
2022-01-15
2022-04-10
2022-03-31
Rob Johnson
2022-03-07
2022-07-18
2022-03-31
Rob Johnson
2022-03-07
2022-07-18
2022-04-30
Rob Johnson
2022-03-07
2022-07-18
2022-05-31
etc...
I tried connecting the Records table with a Calendar table i have that has End of Month data for each day for several years back but can't figure this out. The Calendar table looks something like this..
Date
EndMonth
2022-01-01
2022-01-31
2022-01-02
2022-01-31
.....
JOINing two tables should give the desired result.
You didn't mention a table name for your initial table,
so I will refer to it as the person table.
Your calendar table is a good start.
I don't believe you need the Date column.
Just a single EndMonth column should suffice.
JOIN person against calendar,
WHERE EndMonth BETWEEN StartDate AND EndDate.
And you're done!
OP reports that this works fine:
SELECT P.Name, P.StartDate, P.EndDate, C.EndMonth
FROM PERSON P, CALENDAR C
WHERE EndMonth BETWEEN StartDate AND EndDate;
Well, this is exactly what the Teradata's proprietary EXPAND ON syntax is used for, no need for a calendar table:
SELECT
t.*
,pd -- EXPAND ON returns a period
,begin(pd) -- only show the start of the period
FROM records AS t
-- create a period on-the-fly, adjust the end date as periods exclude the end
EXPAND ON PERIOD(StartDate, Next(EndDate)) AS pd
BY ANCHOR MONTH_END -- return one row per month
Related
I've got a table where we have registries of employees and where they have worked. In each row, we have the employee's starting date on that place. It's something like this:
Employee ID
Name
Branch
Start Date
1
John Doe
234
2018-01-20
1
John Doe
300
2019-03-20
1
John Doe
250
2022-01-19
2
Jane Doe
200
2019-02-15
2
Jane Doe
234
2020-05-20
I need a query where the data returned looks for the next value, making the starting date on the next branch as the end of the current. Eg:
Employee ID
Name
Branch
Start Date
End Date
1
John Doe
234
2018-01-20
2019-03-20
1
John Doe
300
2019-03-20
2022-01-19
1
John Doe
250
2022-01-19
---
2
Jane Doe
200
2019-02-15
2020-05-20
2
Jane Doe
234
2020-05-20
---
When there is not another register, we assume that the employee is still working on that branch, so we can leave it blank or put a default "9999-01-01" value.
Is there any way we can achieve a result like this using only SQL?
Another approach to my problem would be a query that returns only the row that is in a range. For example, if I look for what branch John Doe worked in 2020-12-01, the query should return the row that shows the branch 300.
You can use LEAD() to peek at the next row, according to a subgroup and ordering within it.
For example:
select
t.*,
lead(start_date) over(partition by employee_id order by start_date) as end_date
from t
I have table of EMPLOYEE , in which I need to show the salary from this month to this month .
Suppose I have dates eg. from date 17/01/2020 and to date 18/02/2020 I need monthly data between these two dates like from 17th JAN to 30th JAN one data and from 1st FEB to 28th FEB.
Please suggest some query i trying it but not able to fetch between two dates.
select add_months (to_date(from_date,'dd/mm/yyyy' ), - (level-1)), 'Mon yy') as MONTH,SALARAY from EMPLOYE_BG where CREATED_DATE between TO_DATE('17/01/2020','dd/mm/yyyy')
and to_date('10/03/2020','dd/mm/yyyy')
O/P:
MONTH SALARY
----------------
JAN-20 30000
FEB-20 50000
MAR-20 60000
like this i am expecting the result
SELECT * FROM EMPLOYE_BG
SALARY EMPNAME CREATED_DATE
---------------------------------
30000 JACK 07/01/2020
30000 SWETA 08/01/2020
30000 RAM 08/01/2020
40000 JOHN 01/02/2020
60000 SIMON 10/03/2020
70000 KIRA 11/04/2020
this is table details
I have a db with 6 tables. Each table has a list of date and datetime columns as shown below
Table 1 Table 2 .... Table 6
Date_of_birth Exam_date exam_datetime Result_date Result_datetime
2190-01-13 2192-01-13 2192-01-13 09:00:00 2194-04-13 2194-04-13 07:12:00
2184-05-21 2186-05-21 2186-05-21 07:00:00 2188-02-03 2188-02-03 09:32:00
2181-06-17 2183-06-17 2183-06-17 05:00:00 2185-07-23 2185-07-23 12:40:00
What I would like to do is shift all these future days back to the past date (definitely has to be less than the current date) but retain the same chronological order. Meaning, we can see that the person was born first, then he took the exam, and finally, he got his results.
In addition, I should be able to revert the changes and get back the future dates again.
I expect my output to be something like below
Stage 1 - shift back to old days (it can be any day but it has to be in the past and retain chronological order)
Table 1 Table 2 .... Table 6
Date_of_birth Exam_date exam_datetime Result_date Result_datetime
1990-01-13 1992-01-13 1992-01-13 09:00:00 1994-04-13 1994-04-13 07:12:00
1984-05-21 1986-05-21 1986-05-21 07:00:00 1988-02-03 1988-02-03 09:32:00
1981-06-17 1983-06-17 1983-06-17 05:00:00 1985-07-23 1985-07-23 12:40:00
Stage 2 - Shift forward to future days as how it was earlier
Table 1 Table 2 .... Table 6
Date_of_birth Exam_date exam_datetime Result_date Result_datetime
2190-01-13 2192-01-13 2192-01-13 09:00:00 2194-04-13 2194-04-13 07:12:00
2184-05-21 2186-05-21 2186-05-21 07:00:00 2188-02-03 2188-02-03 09:32:00
2181-06-17 2183-06-17 2183-06-17 05:00:00 2185-07-23 2185-07-23 12:40:00
Subtract two centuries:
update table1
set date_of_birth = date_of_birth - interval '200 year';
You can do something similar for all the other dates.
I have the following table:
id | decided_at | reviewer
1 2020-08-10 13:00 john
2 2020-08-10 14:00 john
3 2020-08-10 16:00 john
4 2020-08-12 14:00 jane
5 2020-08-12 17:00 jane
6 2020-08-12 17:50 jane
7 2020-08-12 19:00 jane
What I would like to do is get the difference between the min and max for each day and get the total count from the id's that are the min, the range between min and max, and the max. Currently, I'm only able to get this data for the past day.
Desired output:
Date | Time(h) | Count | reviewer
2020-08-10 3 3 john
2020-08-12 5 4 jane
From this, I would like to get the average show this data over the past x number of days.
Example:
If today was the 13th, filter on the past 2 days (48 hours)
Output:
reviewer | reviews/hour
jane 5/4 = 1.25
Example 2:
If today was the 13th, filter on the past 3 days (48 hours)
reviewer | reviews/hour
john 3/3 = 1
jane 5/4 = 1.25
Ideally, if this is possible in LookML without the use of a derived table, it would be nicest to have that. Otherwise, a solution in SQL would be great and I can try to convert to LookerML.
Thanks!
In SQL, one solution is to use two levels of aggregation:
select reviewer, sum(cnt) / sum(diff_h) review_per_hour
from (
select
reviewer,
date(decided_at) decided_date,
count(*) cnt,
timestampdiff(hour, min(decided_at), max(decided_at)) time_h
from mytable
where decided_at >= current_date - interval 2 day
group by reviewer, date(decided_at)
) t
group by reviewer
The subquery filters on the date range, aggregates by reviewer and day, and computes the number of records and the difference between the minimum and the maximum date, as hours. Then, the outer query aggregates by reviewer and does the final computation.
The actual function to compute the date difference varies across databases; timestampdiff() is supported in MySQL - other engines all have alternatives.
I have the below set of data which represents employee sick/absence days over a period (12 months) of time, in a table named Absence:
Day Date DaysSick OccasionsSick Notes
Tuesday 2016-09-27 1 Lisa A working today
Thursday 2016-09-29 1 Lisa sick today Celeste
Thursday 2017-01-05 1 Lisa sick today
I would like to update the OccasionsSick column based upon the instances of being sick. So i would have the following:
Day Date DaysSick OccasionsSick Notes
Tuesday 2016-09-27 1 1 Lisa A working today
Thursday 2016-09-29 1 Lisa sick today Celeste
Thursday 2017-01-05 1 1 Lisa sick today
So, the first two entries are the same period of sick leave, so i need a 1 in the first row, and the last entry is a separate sick period, so a 1 again.
Now, in order to establish a sick period there would be a reference to a roster table containing the below:
Date RosterType
2016-09-27 Sick
2016-09-28 Day Off
2016-09-29 Sick
2016-09-30 Normal
So the 27th and 29th were sick days, but the 28th was a standard day off, which is a likely occurrence, so using consecutive days is not an option. I need to be able to look for sick days until a "normal" RosterType is found, this then breaks the sick period. This 1 then needs to be assigned as per the desired result set.
What is the best way of updating the data here? I have come up with a big blank on this, apart from the logic of determining a sick period.
I am presenting this data in Excel with VBA, so it could also be easier to assign the sick periods in VBA, as opposed to SQL for the raw data
Please check this out.
This assumes that there is an entry in the roster for each day.
Basically I'm just building a period and counting the days in the roster.
If there are normal days in between it counts as a new period.
WITH CTE AS (
SELECT
[day]
,[date]
,LAG(date, 1) over (order by date) datebefore
,[dayssick]
FROM [dbo].[absence]
)
SELECT
*
,CASE WHEN ((SELECT COUNT(1) FROM [dbo].[rostertype] WHERE date < c.date AND date > c.datebefore AND rostertype = 'Normal') > 0
OR c.datebefore IS NULL) THEN 1 ELSE 0 END OccasionsSick
FROM CTE c