SQL last 6 months visits - sql

Purpose of the report: Identify patients who did not have dental cleanings in the last 6 months
What would be the best approach to write a sql script?
Patients table
patient_id
patient_name
11
Jason Strong
22
Ryan Smith
33
Casey Hammer
Visits table
v_id
patient_id
reason_visit
date_of_visit
1
11
medical
01/01/2021
2
22
dental cleaning
11/10/2020
3
22
annual
01/01/2021
4
11
dental cleaning
5/10/2021
5
11
annual
5/1/2021
Expected
patient_id
patient_name
22
Ryan Smith
33
Casey Hammer
Casey is on the list because she is not in the visits table meaning she never received a cleaning from our office.
Ryan Smith is on the list because it is time for his cleaning.
I was also thinking what if the patient did not have an appointment in the last 6 months but had an future appointment for dental cleaning. I would want to exclude that.

in postgresql:
select * from Patients p
where not exists (
select 1 from Visits v
where v.patient_id = p.patient_id
and reason_visit = 'dental cleaning'
and date_of_visit < now() - interval '6 month'
)
in sql server replace now() - interval '6 month' with dateadd(month, -6,getdate())
in mysql date_add(now(), interval -6 month)

Related

Oracle SQL - count number of active/open tickets per hour by day

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

How to measure an average count from a set of days each with their own data points, in SQL/LookerML

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.

Logical error in selecting rows with correct output

I understand the basics but I am new to DBMSs and I'm learning in a course.
Here is the assignment question:
Write a query to display the number of sales that were made in the last 40 months with the below table:
SALEID SID SLDATE
1001 1 01-JAN-14
1002 5 02-JAN-14
1003 4 01-FEB-14
1004 1 01-MAR-14
1005 2 01-FEB-14
1006 1 01-JUN-15
My query is:
select count(sldate) as sale_count
from sale
where sldate >= add_months(sysdate, -40)
The output expected and that I get is:
SALE_COUNT
0
But I get an error message:
Error: Your query output matches expected result, but there are logical errors.
I'm not sure where I got the logic wrong.
The 'last 40 months' is ambiguous.
There are several interpretation of 'what does last n months from date x mean' and oracle''s add_months does not have monopoly on that (in fact most people would say it doesn't work as expected, just wait till the 30.06 and ask somebody 'what was the date a month ago' :) )
Imagine today is 20 of april.
Does 'last month' include 15, 20, 21, or 25 of march?
Does it include 02 of april?
That depends, someone could say that 'last month' is from 21 of march to 20 of april.
Someone could say, that 'last month' from 01.03 to today.
Someone could say, that 'last month' starts from 01.04.
Someone could say, that 'last month' means whole march, but not a single day of april.
It gets even trickier when 'today' is close to the end of the month, especially in march.
Don't be hard on yourself just because you couldn't read mind of someone who wrote the assignment ;)
I've wrote a query showing how different approches might yield different results.
CREATE OR REPLACE FUNCTION temp_can_subst_interval_months(p_date date, p_n_of_months number) RETURN NUMBER AS
V_date DATE;
BEGIN
V_Date := p_date - (NUMTOYMINTERVAL(p_n_of_months, 'month'));
RETURN 1;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
with all_days as (
select to_date('2016-01-01', 'YYYY-MM-DD') + (level - 1) as d
from dual
connect by level < 1462
),
all_days_2 as (
select d date_of_query_being_run,
add_months(d, -40)as min_date_your_approach,
add_months(d, -40) + 1 as min_date_your_approach_2, -- same, but exclude the first day
trunc(add_months(d, -40), 'mm') as min_date_whole_month,
case when temp_can_subst_interval_months(d, 40) = 1 then
d - (interval '40' month)
else null
end as min_date_interval_approach
from all_days ad
order by ad.d
)
select ads.*
from all_days_2 ads
;
The most interesting results are when your approach differs from interval approach:
1 (sysdate) 2 (yours) 3 4 5 (interval)
31.01.2016 30.09.2012 01.10.2012 01.09.2012
29.02.2016 31.10.2012 01.11.2012 01.10.2012 29.10.2012
31.03.2016 30.11.2012 01.12.2012 01.11.2012
30.04.2016 31.12.2012 01.01.2013 01.12.2012 30.12.2012
29.06.2016 28.02.2013 01.03.2013 01.02.2013
30.06.2016 28.02.2013 01.03.2013 01.02.2013
31.08.2016 30.04.2013 01.05.2013 01.04.2013
30.09.2016 31.05.2013 01.06.2013 01.05.2013 30.05.2013
31.10.2016 30.06.2013 01.07.2013 01.06.2013
30.11.2016 31.07.2013 01.08.2013 01.07.2013 30.07.2013
31.01.2017 30.09.2013 01.10.2013 01.09.2013
28.02.2017 31.10.2013 01.11.2013 01.10.2013 28.10.2013
31.03.2017 30.11.2013 01.12.2013 01.11.2013
30.04.2017 31.12.2013 01.01.2014 01.12.2013 30.12.2013
29.06.2017 28.02.2014 01.03.2014 01.02.2014
30.06.2017 28.02.2014 01.03.2014 01.02.2014
31.08.2017 30.04.2014 01.05.2014 01.04.2014
30.09.2017 31.05.2014 01.06.2014 01.05.2014 30.05.2014
31.10.2017 30.06.2014 01.07.2014 01.06.2014
30.11.2017 31.07.2014 01.08.2014 01.07.2014 30.07.2014
31.01.2018 30.09.2014 01.10.2014 01.09.2014
28.02.2018 31.10.2014 01.11.2014 01.10.2014 28.10.2014
31.03.2018 30.11.2014 01.12.2014 01.11.2014
30.04.2018 31.12.2014 01.01.2015 01.12.2014 30.12.2014
29.06.2018 28.02.2015 01.03.2015 01.02.2015
30.06.2018 28.02.2015 01.03.2015 01.02.2015
31.08.2018 30.04.2015 01.05.2015 01.04.2015
30.09.2018 31.05.2015 01.06.2015 01.05.2015 30.05.2015
31.10.2018 30.06.2015 01.07.2015 01.06.2015
30.11.2018 31.07.2015 01.08.2015 01.07.2015 30.07.2015
31.01.2019 30.09.2015 01.10.2015 01.09.2015
28.02.2019 31.10.2015 01.11.2015 01.10.2015 28.10.2015
31.03.2019 30.11.2015 01.12.2015 01.11.2015
30.04.2019 31.12.2015 01.01.2016 01.12.2015 30.12.2015
30.06.2019 29.02.2016 01.03.2016 01.02.2016
31.08.2019 30.04.2016 01.05.2016 01.04.2016
30.09.2019 31.05.2016 01.06.2016 01.05.2016 30.05.2016
31.10.2019 30.06.2016 01.07.2016 01.06.2016
30.11.2019 31.07.2016 01.08.2016 01.07.2016 30.07.2016
Side note:
Maybe the table contains something like 'future expected sales' and they want you to filter out dates later than sysdate ;)?

Showing Null Value Based on Three Tables

I’m working on showing employees that have not entered in any hours for a previous week. I’m currently working with three tables. One table is a calendar that has the first date of each week. The week format is Sunday to Saturday. The second table is the list of hours entered. The Time table contains the date the time was entered and the employees name. The third table is the list of all the employees. I can’t seem to get the joins to work how I would like them to. The end result I would like to see that Bob entered time in week 7 and 8, but week 9 is null. Thank you for your help. Its greatly appreciated.
Current Code
SELECT
d.Resource
,SUM(p.Hours) AS Hours
,m.[WeeksSundayToSaturday]
,DatePart(wk, m.[WeeksSundayToSaturday]) AS WeekNumber
FROM CalendarWeeks m
LEFT JOIN [TimeTracking] p ON
(m.[WeeksSundayToSaturday] BETWEEN p.Date AND p.Date + 7)
RIGHT JOIN [DepartmentMembers] d ON
d.Resource = p.CreatedBy
GROUP BY
d.Resource
,m.WeeksSundayToSaturday
Data Tables
Department Members
Name Department
Bob Engineer
Sue HR
John Operations
Time Tracking
Resource Hours Date
Bob 13 2/9/2014
Sue 12 2/10/2014
John 2 2/11/2014
Bob 6 2/12/2014
Bob 8 2/13/2014
John 8 2/14/2014
John 8 2/15/2014
Bob 8 2/16/2014
Bob 1 2/17/2014
Bob 2 2/18/2014
Bob 1 2/19/2014
Bob 8 2/20/2014
Bob 9 2/21/2014
Bob 6 2/22/2014
Sue 8 2/23/2014
John 2 2/24/2014
Calendar
WeeksSundayToSaturday
1/5/2014
1/12/2014
1/19/2014
1/26/2014
2/2/2014
2/9/2014
2/16/2014
2/23/2014
3/2/2014
3/9/2014
3/16/2014
3/23/2014
3/30/2014
Desired Result
Bob
Week 7 = 27
Week 8 = 35
Week 9 = NULL
Your above query is giving compilation error, please try below query i think it will help you
SELECT
d.Resource
,SUM(p.Hours) AS Hours
,m.[WeeksSundayToSaturday]
,DatePart(wk, m.[WeeksSundayToSaturday]) AS WeekNumber
FROM CalendarWeeks m
LEFT JOIN [TimeTracking] p ON (p.Date BETWEEN
m.[WeeksSundayToSaturday] AND Dateadd(d,6, m.[WeeksSundayToSaturday])
RIGHT JOIN [DepartmentMembers] d ON d.Resource = p.CreatedBy
GROUP BY d.Resource ,m.WeeksSundayToSaturday

Postgres sql 8.4 Use of Time Difference and Date Difference Separately

I Have this question and i can not resolve it because i think thats is impossible in sql
I have this table
Shedule
id_emp Name `time initial` time end
1 juan` 09:00` 12:00
2 Francisco 10:00 11:30
3 Sebastian 11:00 15:00
6 Roberto 15:00 18:00
Suspension
id_emp suspension_initial suspension_end
1 2013-06-01 2013-06-01
2 2013-06-01 2013-06-03
3 2013-06-03 2013-06-04
6 2013-06-01 2013-06-01
2 2013-07-01 2013-07-01
3 2013-07-05 2013-07-05
1 2013-07-06 2013-07-06
I want to catch hours worked ((time_end- time_initial) - suspension) (if i have 1 day of suspension is one unit of hour example: Juan Worked 3 hours per day and he has 1 day of suspension on june and one day of suspension on july. So i assume in one month he works 3*20 (Hours*dayworked) - 3 hours june and 3 hours july
How can i get this result
id_emp name ` June-2013 July-2013
1 Juan 57 (hours Worked) 57 (hours Worked)
2 Francisco 24 (hours worked) 27 (hours worked)
3 Sebastián
6 Roberto
Here is the SQLFiddel Demo
Below is the query which you can try
select EmpHrs.ID_EMP,
EmpHrs.Name,
(
(EmpHrs.NOOFHRS*20)-
(EmpHrs.NOOFHRS*
JuneSuspension.MONTHSUSPENSION)
) as "June-2013",
(
(EmpHrs.NOOFHRS*20)-
(EmpHrs.NOOFHRS*
JulySuspension.MONTHSUSPENSION)
) as "July-2013"
from
(
select ID_EMP,NAME,
Extract(Hours from time_end-time_initial)+
Extract(Minutes from time_end-time_initial)/60 as NoOfHrs
from schedule
) EmpHrs
Left join
(select ID_EMP,to_char(to_timestamp (Extract(Month from suspension_initial)::text, 'MM'),'Mon') as MonthIni,(suspension_end::date - suspension_initial::date)+1 MonthSuspension
from suspension
where Extract(Month from suspension_initial) = 6) JuneSuspension
On JuneSuspension.ID_EMP = EmpHrs.ID_EMP
Left join
(select ID_EMP,to_char(to_timestamp (Extract(Month from suspension_initial)::text, 'MM'),'Mon') as MonthIni,(suspension_end::date - suspension_initial::date)+1 MonthSuspension
from suspension
where Extract(Month from suspension_initial) = 7) JulySuspension
On JulySuspension.ID_EMP = EmpHrs.ID_EMP