I have a dataset from oracle db that looks something like this:
ticket_num start_date repair_date
1 1/1/2021 02:05:15 1/4/2021 09:30:00
2 1/2/2021 12:15:45 1/2/2021 14:03:00
3 1/2/2021 12:20:00 1/2/2021 13:54:00
I need to calculate the number of active tickets in an hour time slot. So if the ticket was opened before that hour, and closed after the hour it would be counted. All days and hours need to be represented regardless if there are active tickets open during that time. The expected output is:
month day hour #active_tix
1 1 2 1
1 1 3 1
...
1 2 12 3
1 2 13 3
1 2 14 2
1 2 15 1
...
1 4 9 1
1 4 10 0
Any help would be greatly appreciated.
You need a calendar table. In the query below it is created on the fly
select c.hstart, count(t.ticket_num) n
from (
-- create calendar on the fly
select timestamp '2021-01-01 00:00:00' + NUMTODSINTERVAL(level-1, 'hour') hstart
from dual
connect by timestamp '2021-01-01 00:00:00' + NUMTODSINTERVAL(level-1, 'hour') < timestamp '2022-01-01 00:00:00'
) c
left join mytable t on t.start_date < c.hstart and t.repair_date >= c.hstart
group by c.hstart
order by c.hstart
Related
I need to show the number of valid inspectors we have by month over the last five years. Inspectors are considered valid when the expiration date on their certification has not yet passed, recorded as the month end date. The below SQL code is text of the query to count valid inspectors for January 2017:
SELECT Count(*) AS RecordCount
FROM dbo_Insp_Type
WHERE (dbo_Insp_Type.CERT_EXP_DTE)>=#2/1/2017#);
Rather than designing 60 queries, one for each month, and compiling the results in a final table (or, err, query) are there other methods I can use that call for less manual input?
From this sample:
Id
CERT_EXP_DTE
1
2022-01-15
2
2022-01-23
3
2022-02-01
4
2022-02-03
5
2022-05-01
6
2022-06-06
7
2022-06-07
8
2022-07-21
9
2022-02-20
10
2021-11-05
11
2021-12-01
12
2021-12-24
this single query:
SELECT
Format([CERT_EXP_DTE],"yyyy/mm") AS YearMonth,
Count(*) AS AllInspectors,
Sum(Abs([CERT_EXP_DTE] >= DateSerial(Year([CERT_EXP_DTE]), Month([CERT_EXP_DTE]), 2))) AS ValidInspectors
FROM
dbo_Insp_Type
GROUP BY
Format([CERT_EXP_DTE],"yyyy/mm");
will return:
YearMonth
AllInspectors
ValidInspectors
2021-11
1
1
2021-12
2
1
2022-01
2
2
2022-02
3
2
2022-05
1
0
2022-06
2
2
2022-07
1
1
ID
Cert_Iss_Dte
Cert_Exp_Dte
1
1/15/2020
1/15/2022
2
1/23/2020
1/23/2022
3
2/1/2020
2/1/2022
4
2/3/2020
2/3/2022
5
5/1/2020
5/1/2022
6
6/6/2020
6/6/2022
7
6/7/2020
6/7/2022
8
7/21/2020
7/21/2022
9
2/20/2020
2/20/2022
10
11/5/2021
11/5/2023
11
12/1/2021
12/1/2023
12
12/24/2021
12/24/2023
A UNION query could calculate a record for each of 50 months but since you want 60, UNION is out.
Or a query with 60 calculated fields using IIf() and Count() referencing a textbox on form for start date:
SELECT Count(IIf(CERT_EXP_DTE>=Forms!formname!tbxDate,1,Null)) AS Dt1,
Count(IIf(CERT_EXP_DTE>=DateAdd("m",1,Forms!formname!tbxDate),1,Null) AS Dt2,
...
FROM dbo_Insp_Type
Using the above data, following is output for Feb and Mar 2022. I did a test with Cert_Iss_Dte included in criteria and it did not make a difference for this sample data.
Dt1
Dt2
10
8
Or a report with 60 textboxes and each calls a DCount() expression with criteria same as used in query.
Or a VBA procedure that writes data to a 'temp' table.
So if we start a month on a weekend the first day becomes the weekend and it should roll over to weekday and similarly Holidays should roll back to previous day.
Date RecognizedBusinessDateKey RecognizedBusinessDateNumber
7/28/2020 20200728 19
7/29/2020 20200729 20
7/30/2020 20200730 21
7/31/2020 20200731 22
8/1/2020 20200803 1
8/2/2020 20200803 1
8/3/2020 20200803 1
8/4/2020 20200804 2
Date RecognizedBusinessDateKey RecognizedBusinessDateNumber
5/28/2020 20200528 19
5/29/2020 20200529 20
5/30/2020 20200529 20
5/31/2020 20200529 20
6/1/2020 20200601 1
6/2/2020 20200602 2
6/3/2020 20200603 3
6/4/2020 20200604 4
Date RecognizedBusinessDateKey RecognizedBusinessDateNumber
6/4/2020 20200604 4
6/5/2020 20200605 5
6/6/2020 20200605 5
6/7/2020 20200608 6
6/8/2020 20200608 6
6/9/2020 20200609 7
Data is looking like this in table
I tried the below query
SELECT
d.Date
,d.DateKey
,d.IsBusinessDay
,d.MonthKey
,ISNULL(MAX(d2.DateKey),d.DateKey) AS RecognizedBusinessDateKey
,DENSE_RANK() OVER(PARTITION BY d.MonthKey ORDER BY ISNULL(MAX(d2.DateKey),d.DateKey)) AS RecognizedBusinessDateNumber
FROM dbo.DimDate d
LEFT JOIN dbo.DimDate d2
ON d2.MonthKey <= d.DateKey
WHERE d2.IsBusinessDay = 'Business Day'
AND d2.DateKey > 0
AND d2.Date BETWEEN '8/1/2020' AND '8/31/2020'
GROUP BY
d.Date
,d.DateKey
,d.IsBusinessDay
,d.MonthKey
How to count employees per hour working in between intime and outtime hours.
I have below table format with intime,outtime of employee .
My Table :
emp_reader_id att_date in_time out_time Shift_In_Time Shift_Out_Time
111 2020-03-01 2020-03-01 08:55:24.000 2020-03-01 10:26:56.000 09:00:00.0000000 10:30:00.0000000
112 2020-03-01 2020-03-01 08:45:49.000 2020-03-01 11:36:14.000 09:00:00.0000000 11:30:00.0000000
113 2020-03-01 2020-03-01 10:58:19.000 2020-03-01 13:36:31.000 09:00:00.0000000 12:00:00.0000000
Need to count the employee in the below format.
Expected Output:
Period Working Employee Count
0 - 1 0
1 - 2 0
2 - 3 0
3 - 4 0
4 - 5 0
5 - 6 0
6 - 7 0
7 - 8 0
8 - 9 2
9 - 10 2
10 - 11 3
11 - 12 2
12 - 13 1
13 - 14 1
14 - 15 0
15 - 16 0
16 - 17 0
17 - 18 0
18 - 19 0
19 - 20 0
20 - 21 0
21 - 22 0
22 - 23 0
23 - 0 0
I tried with below query with my raw data , but it will not work i need from above table
SELECT
(DATENAME(hour, C.DT) + ' - ' + DATENAME(hour, DATEADD(hour, 2, C.DT))) as PERIOD,
Count(C.EVENTID) as Emp_Work_On_Time
FROM
trnevents C
WHERE convert(varchar(50),C.DT,23) ='2020-03-01'
GROUP BY (DATENAME(hour, C.DT) + ' - ' +
DATENAME(hour, DATEADD(hour, 2, C.DT)))
you need to have a list of hours (0 to 23) and then left join to your table.
The following query uses recursive cte to generate that list. You may also use VALUES constructor or TALLY table. Which will gives same effect
; with hours as
(
select hour = 0
union all
select hour = hour + 1
from hours
where hour < 23
)
select convert(varchar(2), h.hour) + ' - ' + convert(varchar(2), (h.hour + 1) % 24) as [Period],
count(t.emp_reader_id) as [Working Employee Count]
from hours h
left join timesheet t on h.hour >= datepart(hour, in_time)
and h.hour <= datepart(hour, out_time)
group by h.hour
Demo : db<>fiddle
Hope that might help but take a look how shift in and shift out are in the code... seems to me its automatic so it could have all you need
SELECT COUNT(Idemp) from aaShiftCountEmp WHERE in_time<'2020-03-01 09:00:00.000' AND out_time>'2020-03-01 10:00:00.000'
this is just example for 9h to 10h but u can make it auto,
btw are u sure that this shoul not show SHIFT ppl cOUNT? i mean u sure 0-1, 1-2 instead of 0-1.30, 1.30-3?? etc?
I am trying to calculate the churn rate from a data that has customer_id, group, date. The aggregation is going to be by id, group and date. The churn formula is (customers in previous cohort - customers in last cohort)/customers in previous cohort
customers in previous cohort refers to cohorts in before 28 days
customers in last cohort refers to cohorts in last 28 days
I am not sure how to aggregate them by date range to calculate the churn.
Here is sample data that I copied from SQL Group by Date Range:
Date Group Customer_id
2014-03-01 A 1
2014-04-02 A 2
2014-04-03 A 3
2014-05-04 A 3
2014-05-05 A 6
2015-08-06 A 1
2015-08-07 A 2
2014-08-29 XXXX 2
2014-08-09 XXXX 3
2014-08-10 BB 4
2014-08-11 CCC 3
2015-08-12 CCC 2
2015-03-13 CCC 3
2014-04-14 CCC 5
2014-04-19 CCC 4
2014-08-16 CCC 5
2014-08-17 CCC 3
2014-08-18 XXXX 2
2015-01-10 XXXX 3
2015-01-20 XXXX 4
2014-08-21 XXXX 5
2014-08-22 XXXX 2
2014-01-23 XXXX 3
2014-08-24 XXXX 2
2014-02-25 XXXX 3
2014-08-26 XXXX 2
2014-06-27 XXXX 4
2014-08-28 XXXX 1
2014-08-29 XXXX 1
2015-08-30 XXXX 2
2015-09-31 XXXX 3
The goal is to calculate the churn rate every 28 days in between 2014 and 2015 by the formula given above. So, it is going to be aggregating the data by rolling it by 28 days and calculating the churn by the formula.
Here is what I tried to aggregate the data by date range:
SELECT COUNT(distinct customer_id) AS count_ids, Group,
DATE_SUB(CAST(Date AS DATE), INTERVAL 56 DAY) AS Date_min,
DATE_SUB(CURRENT_DATE, INTERVAL 28 DAY) AS Date_max
FROM churn_agg
GROUP BY count_ids, Group, Date_min, Date_max
Hope someone will help me with aggregation and churn calculation. I want to simply deduct the aggregated count_ids to deduct it from the next aggregated count_ids which is after 28 days. So this is going to be successive deduction of the same column value (count_ids). I am not sure if I have to use rolling window or simple aggregation to find the churn.
As corrected by #jarlh, it's not 2015-09-31 but 2015-09-30
You can use this to create 28 days calendar:
create table daysby28 (i int, _Date date);
insert into daysby28 (i, _Date)
SELECT i, cast('01-01-2014'as date) + i*INTERVAL '28 day'
from generate_series(0,50) i
order by 1;
After you use #jarlh churn_agg table creation he sent with the fiddle, with this query, you get what you want:
with cte as
(
select count(Customer) as TotalCustomer, Cohort, CohortDateStart From
(
select distinct a.Customer_id as Customer, b.i as Cohort, b._Date as CohortDateStart
from churn_agg a left join daysby28 b on a._Date >= b._Date and a._Date < b._Date + INTERVAL '28 day'
) a
group by Cohort, CohortDateStart
)
select a.CohortDateStart,
1.0*(b.TotalCustomer - a.TotalCustomer)/(1.0*b.TotalCustomer) as Churn from cte a
left join cte b on a.cohort > b.cohort
and not exists(select 1 from cte c where c.cohort > b.cohort and c.cohort < a.cohort)
order by 1
The fiddle of all together is here
I have some tables (samples are brought here) like this
scores (the score is calculated once in each month for each branch_cust in the 28 for specific month)
Branch_cust model_date score
1 28/12/2013 4
1 28/01/2014 3
1 28/02/2014 2
1 28/03/2014 7
1 28/04/2014 3
1 28/05/2014 5
1 28/06/2014 6
2 28/12/2013 9
2 28/01/2014 10
2 28/02/2014 12
2 28/03/2014 11
2 28/04/2014 10
2 28/05/2014 7
2 28/06/2014 8
loans:
Branch_cust agreement_date
1 05-01-2014
1 29-01-2014
2 27-02-2014
2 28-02-2014
Loans:
desired output:
Branch_cust agreement_date loan_open_score
1 05-01-2014 4
1 29-01-2014 3
2 27-02-2014 10
2 28-02-2014 12
Logic to create the loan_open_score :
If the day in the month of the agreement_date is less then "28" then bring the score of the month previous to the month of the agreement date.
If the day is greater or equal to "28" then bring the score for the month equal to the month of the agreement date.
Example: In the sample data for branch_cust = 1 the agreement_date was 05-01-2014 - meaning - day = 5 so I need to go back to Dec 2013 and take the score from there.
Any help how to do this? thank's. I was thinking of "join" and then substract 1 in "case of.." but I don't know how to handle the case when the date is 'dd-01-YYYY' in sql-teradata.
updated : column data type of the dates are dates.
trunc(agreement_date,'mon') + 27 returns the 28th of the current month. Now you can apply some logic and join on this calculated date:
case when trunc(agreement_date,'mon') + 27 > agreement_date
then add_months(trunc(agreement_date,'mon') + 27,-1)
else trunc(agreement_date,'mon') + 27
end
Another option would be to get the latest model_date per agreement date and join it to the scores table. This way you don't have to manipulate dates.
select t.branch_cust,t.agreement_Date,s.score
from scores s
join (select distinct l.branch_cust,l.agreement_Date
,max(s.model_Date) over(partition by l.branch_cust,l.agreement_Date) as max_model_Date
from scores s
join loans l on s.branch_cust=l.branch_cust and l.agreement_Date >= s.model_Date
) t
on s.branch_cust=t.branch_cust and s.model_Date=t.max_model_Date
select *
from scores as s
join loans as l
on l.Branch_cust =
s.Branch_cust
and l.model_date =
add_months
(
trunc(S.agreement_date,'mm')+27
,case when extract(day from s.agreement_date) < 28 then -1 else 0 end
)