Get name of person having activity in every month - Oracle SQL - sql

I have log table where there is are records with user id and the date for a specific activity done. I want to get names of users having activity every month. I am using the following query
select distinct(employeeid) from transactions
where eventdate between '01-OCT-13' AND '23-OCT-13'
and eventdate between '01-SEP-13' AND '01-OCT-13'
and eventdate between '01-AUG-13' AND '01-SEP-13'
and eventdate between '01-JUL-13' AND '01-AUG-13';
But this is doesn't work. Can someone please suggest any improvement?
Edit:
Since my questions seems to be a little confusing, here is an example
EmployeeID | Timestamp
a | 01-Jul-13
b | 01-Jul-13
a | 01-Aug-13
c | 01-Aug-13
a | 01-Sep-13
d | 01-Sep-13
a | 01-Oct-13
a | 01-Oct-13
In the above table, we can see that employee "a" has activity in all the months from July till October. So I want to find a list of all such employees.

You can use COUNT as analytical function and get the number of months for each employee and total number of months. Then select only those employees where both counts match.
select distinct employeeid
from (
select employeeid,
count(distinct trunc(eventdate,'month')) --count of months for each employee
over (partition by employeeid) as emp_months,
count(distinct trunc(eventdate,'month')) --count of all months
over () as all_months,
from transactions
)
where emp_months = all_months;

Wish I could give you the code, but i'm in a bit of a hurry, so this is more of a suggestion.
Have you tried extracting the distinct months (from eventdate), for every user, and if that has 10 rows (assuming it is October, you could dynamically change this), then the employee must of had an event every month.

By very inefficient, I think you mean it doesn't work. The same value can't be both in september, in october, etc.
Anyway, using #LaggKing suggestion, you could try this query:
SELECT employeeid
FROM (
SELECT DISTINCT employeeid, MONTH(eventdate)
FROM transactions
)
HAVING COUNT(*) = MONTH(NOW())
EDIT: You need to take year into account.
SELECT employeeid
FROM (
SELECT DISTINCT employeeid, MONTH(eventdate)
FROM transactions
WHERE YEAR(eventdate) = YEAR(NOW())
)
HAVING COUNT(*) = MONTH(NOW())

Related

Finding id's available in previous weeks but not in current week

How to find if an id which was present in previous weeks but not available in current week on a rolling basis. For e.g
Week1 has id 1,2,3,4,5
Week2 has id 3,4,5,7,8
Week3 has id 1,3,5,10,11
So I found out that id 1 and 2 are missing in week 2 and id 2,4,7,8 are missing in week 3 from previous 2 weeks But how to do this on a rolling window for a large amount of data distributed over a period of 20+ years
Please find the sample dataset and expected output. I am expecting the output to be partitioned based on the week_end Date
Dataset
ID|WEEK_START|WEEK_END|APPEARING_DATE
7152|2015-12-27|2016-01-02|2015-12-27
8350|2015-12-27|2016-01-02|2015-12-27
7152|2015-12-27|2016-01-02|2015-12-29
4697|2015-12-27|2016-01-02|2015-12-30
7187|2015-12-27|2016-01-02|2015-01-01
8005|2015-12-27|2016-01-02|2015-12-27
8005|2015-12-27|2016-01-02|2015-12-29
6254|2016-01-03|2016-01-09|2016-01-03
7962|2016-01-03|2016-01-09|2016-01-04
3339|2016-01-03|2016-01-09|2016-01-06
7834|2016-01-03|2016-01-09|2016-01-03
7962|2016-01-03|2016-01-09|2016-01-05
7152|2016-01-03|2016-01-09|2016-01-07
8350|2016-01-03|2016-01-09|2016-01-09
2403|2016-01-10|2016-01-16|2016-01-10
0157|2016-01-10|2016-01-16|2016-01-11
2228|2016-01-10|2016-01-16|2016-01-14
4697|2016-01-10|2016-01-16|2016-01-14
Excepted Output
Partition1: WEEK_END=2016-01-02
ID|MAX(LAST_APPEARING_DATE)
7152|2015-12-29
8350|2015-12-27
4697|2015-12-30
7187|2015-01-01
8005|2015-12-29
Partition1: WEEK_END=2016-01-09
ID|MAX(LAST_APPEARING_DATE)
7152|2016-01-07
8350|2016-01-09
4697|2015-12-30
7187|2015-01-01
8005|2015-12-29
6254|2016-01-03
7962|2016-01-05
3339|2016-01-06
7834|2016-01-03
Partition3: WEEK_END=2016-01-10
ID|MAX(LAST_APPEARING_DATE)
7152|2016-01-07
8350|2016-01-09
4697|2016-01-14
7187|2015-01-01
8005|2015-12-29
6254|2016-01-03
7962|2016-01-05
3339|2016-01-06
7834|2016-01-03
2403|2016-01-10
0157|2016-01-11
2228|2016-01-14
Please use below query,
select ID, MAX(APPEARING_DATE) from table_name
group by ID, WEEK_END;
Or, including WEEK)END,
select ID, WEEK_END, MAX(APPEARING_DATE) from table_name
group by ID, WEEK_END;
You can use aggregation:
select t.*, max(week_end)
from t
group by id
having max(week_end) < '2016-01-02';
Adjust the date in the having clause for the week end that you want.
Actually, your question is a bit unclear. I'm not sure if a later week end would keep the row or not. If you want "as of" data, then include a where clause:
select t.id, max(week_end)
from t
where week_end < '2016-01-02'
group by id
having max(week_end) < '2016-01-02';
If you want this for a range of dates, then you can use a derived table:
select we.the_week_end, t.id, max(week_end)
from (select '2016-01-02' as the_week_end union all
select '2016-01-09' as the_week_end
) we cross join
t
where t.week_end < we.the_week_end
group by id, we.the_week_end
having max(t.week_end) < we.the_week_end;

Return absolute number, and percentage together

I am trying to calculate the total number of [visits] from my hospital database, so that I can use the result to read from my Python script and send out weekly summary to our team every week. So, I am wondering if anyone can help me out for my query since I am still learning SQL.
Goal Table format:
- Date (prefer dd/mm/yyyy)
- Patient_Name (e.g John)
- Patient_Id (e.g 12345)
- Visits
- Professionals (Categorical Variables: Nurse, Doctor, Assistant Nurse)
So, I want to get a query that can list out total visits by nurse in specific date range and percentage of total visits from all professionals for the specific patient in a week. For example, Nurse visit patient (John) 15 times, and Assistant Nurse visits 10 times while Doctor pay visits 5 times/week, so my final table would be this:
____________________________________________
|____Date_____|__Prof__|__Visits_|___Percen__|
|06/01/2018 | Nurse | 15 | 0.5 |
|02/11/2017 | A-Nurse| 10 | 0.33 |
|19/04/2016 | Nurse | 5 | 0.16 |
|
Below is my SQL Statement on my SSMS, and I used case statement for Professionals data since based on patient needs, sometimes therapists visits instead of nurse/doctor so I would like that part to be dynamic:
SELECT CONVERT(VARCHAR(10), [myDate], 101), SUM([visits]) AS [Date] , [Professionals], ((SELECT [Visits] from MyHospitalTable)* 100 / (Select SUM([Visits]) From MyHospitalTable)) as Percen
FROM
(SELECT
Count(*) as [total],
[Date] as [myDate],
[Patient_id] as [myPatient_Id],
[Patient_Name] as [myPatient_Name],
[visits] as [visits],
CASE
WHEN [Professionals] LIKE '%Nurse%' THEN 'Nurse'
WHEN [Professionals] LIKE '%Therapist%' THEN 'Therapy'
else 'Unknown'
END AS [Professionals]
FROM [MyHospitalTable]
) a
GROUP BY [myDate]
I understand that my query is not correct, and need improvement, and if anyone can please help me out getting the data, that would be awesome.
Thanks in advance.
You can calculate the grand total using window function and find the percentage.
Below give you an idea how to do that. it is not exactly compatible with your table though.
;with ct as (
select MyDate, sum(Visits) Visits
, count(Visits) over (partition by MyDate order by MyDate) TotalVisits
from HospitalTable
group by MyDate
)
select MyDate, Visits, (Visits * 100 / TotalVisits)
from ct

how to find number of active users for say 1 day,2 days, 3 days.....postgreSQL

A distribution of # days active within a week: I am trying to find how many members are active for 1 day, 2days, 3days,…7days during a specific week 3/1-3/7.
Is there any way to use aggregate function on top of partition by?
If not what can be used to achieve this?
select distinct memberID,count(date) over(partition by memberID) as no_of_days_active
from visitor
where date between '"2019-01-01 00:00:00"' and '"2019-01-07 00:00:00"'
order by no_of_days_active
result should look something like this
#Days Active Count
1 20
2 32
3 678
4 34
5 3
6 678
7 2345
I think you want two levels of aggregation to count the number of days during the week:
select num_days_active, count(*) as num_members
from (select memberID, count(distinct date::date) as num_days_active
from visitor
where date >= '2019-01-01'::date and
date < '2019-01-08'::date
group by memberID
) v
group by num_days_active
order by num_days_active;
Note that I changed the date comparisons. If you have a time component, then between does not work. And, because you included time in the constant, I added an explicit conversion to date for the count(distinct). That might not be necessary, if date is really a date with no time component.
Piggybacking off of #Gordon's answer, I personally like using a with statement for the subqueries:
with dat as (
select distinct
memberID,
count(date) over(partition by memberID) as no_of_days_active
from visitor
where 1=1
and date between '2019-01-01'::date and '2019-01-07'::date
order by no_of_days_active
)
select
no_of_days_active,
count(no_of_days_active) no_of_days_active_cnt
from dat
group by no_of_days_active
order by no_of_days_active

How to get common IDs in each group from a group by SQL clause?

I have data of calls for customers. I want to get those customers between two dates that have activity against every date. They did at least one activity every day. I tried following query.
Following is the query:
select date_id , count (distinct customer_id) from usage_analysis
where usage_direction_type_id = 1
and date_id => 20130608 and date_id <= 20130612
group by date_id
That returns:
DATE_ID COUNT
----------------------------
20130608 23451
20130609 9878
20130610 56122
20130611 7811
20130612 12334
But I want to get those customers that are common in each group. It may happen a person who called on 8 June does not exist on the next day. So I only want those customers that exist in every group.
Any idea who can I do that in SQL?
You can count the distinct dates for each customer. Only customers with five distinct dates would then pass the test. The following provides the list of customers:
select customer_id
from usage_analysis
where usage_direction_type_id = 1 and
date_id >= 20130608 and date_id <= 20130612
group by customer_id
having count(distinct date_id) = 5
#Gordon Linoff answer should be working fine for your situation. When you tried with 2 days, did you make sure to change the count value from 5 to 2?

How to run sql n times increasing variable and after joining results

I've a transact table (historical) with a CreatedDate, this transact is related to employee transact table. (inner join in transact_id)
This being said, comes the problem: I need to query these table and get the state by month , because during the year, the CreatedDate can change. e.g. An employee update in July will create a new line, but this shouldn't affect the March total.
The solution looks like a forech, but how can I join all lines at the end? The result should be something like:
January - $123
February - $234
March - $123
...
I get the last state of each employee with this:
select AllTransact.id_employee, AllTransact.id_department from (
select id_employee, id_department, rank() over (partition by id_employee order by created_date desc) desc_rank
from Transact_Employee TransEmployee
inner join Transact on TransEmployee.ID_Transact = Transact.ID_Transact
and Transact.Status = 8
and Transact.Created_Date < #currentMonth) AllTransact
where desc_rank = 1
*I don't want to copy and past all the code 12 times. :)
You can partition over many columns. rank() OVER (partition BY [id_employee],datepart(month,[Created_Date]) ORDER BY [Created_Date] DESC) will give you what you have now but for each month (and it doesn't care what year that month is in so you either need to partition by year too or add limit on created_date).