简体   繁体   中英

Checking services logs for “working time” users — conditions in having clause

I have a table of service usage by user id that is accompanied by a dimension table including date, day of the week, hour of the day, etc. Each time the user uses the service, a new row is created that logs the time of use.

I want to find users that use the service at least four out of five weekdays, each day logging usage in at least 8 separate hours of the day. These are the "working time" users. How can I best achieve this?

Currently, I am compromising with the having clause below, which does not capture the conditions specified above completely. Rather, it gets the users that use the service for at least 16 weekdays in a month with an average usage of at least 8 hours a day.

select 
a.userId
from SERVICE_LOGS_MTHLY a 
inner join DIM_TIME_OF_DAY b
  on a.TOD_ID = b.TOD_ID
having
  count(distinct (case when b.day_of_week in ('MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY') then a.day end)) >= 16 
  AND
  count(distinct (case when b.day_of_week in ('MONDAY') then a.day||b.hour24 end)) >= 8*count(distinct (case when b.day_of_week in ('MONDAY') then a.day end))
  AND
  count(distinct (case when b.day_of_week in ('TUESDAY') then a.day||b.hour24 end)) >= 8*count(distinct (case when b.day_of_week in ('TUESDAY') then a.day end))
  AND
  count(distinct (case when b.day_of_week in ('WEDNESDAY') then a.day||b.hour24 end)) >= 8*count(distinct (case when b.day_of_week in ('WEDNESDAY') then a.day end))
  AND
  count(distinct (case when b.day_of_week in ('THURSDAY') then a.day||b.hour24 end)) >= 8*count(distinct (case when b.day_of_week in ('THURSDAY') then a.day end))
  AND
  count(distinct (case when b.day_of_week in ('FRIDAY') then a.day||b.hour24 end)) >= 8*count(distinct (case when b.day_of_week in ('FRIDAY') then a.day end))

This involves aggregating an aggregate, that is, it involves two steps. One is to provide how many hours each day a user logs the service and the other to provide the number of weekdays each week.

Using a simple table named Hourly which seems to match minimally the description of your table, see my SQL Fiddle scenario.

The first step is to aggregate hours daily.

select  h.ID, h.StartDate, count(*) as DailyCount
from    Hourly  h
where   DoW in( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday' )
group by h.ID, h.StartDate;

You weren't too clear so this assumes one entry for an hour of use no matter how many times in that hour the user performs a loggable event. Adjust if necessary.

Now just add up for each week how many 8 or greater days. This uses the results of the query above so make that into a CTE or create a view from it if you don't have CTEs available (MySQL).

with
Daily( ID, StartDate, DailyCount )as(
    select  h.ID, h.StartDate, count(*) as DailyCount
    from    Hourly  h
    where   DoW in( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday' )
    group by h.ID, h.StartDate
)
select  d.ID, Sum( case when DailyCount < 8 then 0 else 1 end ) as WeeklyCount
from    Daily   d
group by d.ID, To_Char( d.StartDate, 'iw' );

Now you just check for a WeeklyCount of 4 or more for each user for each week.

Note: the To_Char allows you to group by week. For most DBMSs other than Oracle, this is provided by a DatePart function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM