tags:

views:

219

answers:

7

I am trying to count the number of days of the current week that do not have an event associated with them, but I don't know how to do it.

For example, I count the number of events happening this week with this query:

SELECT COUNT(e.event_id) FROM cali_events e
LEFT JOIN cali_dates d
ON e.event_id = d.event_id
WHERE YEARWEEK(d.date) = YEARWEEK(CURRENT_DATE())

But I only know how to count the days by counting each individual day and summing up the days that return 0, but that's not very elegant.

How could I do it with one query?

+1  A: 

This might be a case for one of those 'value tables' where you create a table with possible days/weeks/whatever and then join for those that DON'T match & count them.

n8wrl
A: 

So you have a Dates table and an Events table?

Would an event_id only show up in the Dates table if there was an event?

If so, couldn't you just do an INNER JOIN?

Jack Marchetti
+10  A: 

This query uses a subquery to find all the unique dates in the joined tables. Then the number of unique dates is subtracted from seven?

--assuming a 7 day week; no mention in the request about workweek.
      SELECT 7 - COUNT(*) AS NumDaysWithoutEvents
        FROM    
        (SELECT DAY(d.date) 
            FROM cali_events e
            LEFT JOIN cali_dates d
            ON e.event_id = d.event_id
            WHERE YEARWEEK(d.date) = YEARWEEK(CURRENT_DATE())
            GROUP BY DAY(d.date)
        ) AS UniqueDates
p.campbell
that return's 10 6's... There are 7 events, and three days without events.
Malfist
Now I get one row of -3!
Malfist
It's a DATETIME so grouping by d.date is useless, they have different time's assigned to them even if they're on the same day.
Malfist
AH HA! GROUP BY DAY(d.date)
Malfist
Sorry, there was no mention of time in the original question.This solution works when you do not include the time. We'll just have to strip the time out of the datetime field in mysql,
p.campbell
Do you need to also strip the time portion in the select? i.e. select Day(d.date)
Jeff Meatball Yang
No, DAY return the day of the month that the DateTime is representing.
Malfist
+1  A: 

Couldn't you write you query to find the distinct dates on which there is an event during the time frame that you're interested in?

Bernard Chen
A: 

I think this will work but I also think there's a solution that uses HAVING.

SELECT COUNT(*) FROM
    (SELECT d.date, count(*) as event_count
    FROM cali_dates d
        LEFT JOIN cali_events e ON d.event_id = e.event_id
    WHERE YEARWEEK(d.date) = YEARWEEK(CURRENT_DATE())
    GROUP BY d.date) t
WHERE t.event_count = 0

Edited to add: this assumes no time portion in d.date, although it would be easy to accommodate that. It also assumes that cali_dates contains a record for every day of the week.

Jamie Ide
returns 0, it should return 3
Malfist
A: 

Flip the query around and select from cali_dates if no records exist in cali_events for an event_id:

select count(*)
  from cali_dates d
 where not exists( select *
                     from cali_events e
                    where d.event_id = e.event_id )
   and YEARWEEK(d.date) = YEARWEEK(CURRENT_DATE())
Paul Morgan
returns 0, should return 3.
Malfist
A: 

Assuming your Cali_Dates table has a row for every day in the week:

From the Cali_Dates table, where it's the current week, find all the rows that have nulls (no events) in the Cali_Events table.

SELECT sum(case when e.event_id is null then 1 else 0 end)
FROM cali_dates d
LEFT JOIN cali_events e
ON e.event_id = d.event_id
WHERE YEARWEEK(d.date) = YEARWEEK(CURRENT_DATE())
GROUP BY d.date

Otherwise, you'd have to declare the number of days in the week, like in pcambell's answer:

Edit: forgot to add the group by

Jeff Meatball Yang