tags:

views:

96

answers:

4

Hi folks,

I asked a question regarding joins yesterday. However although that answer my initial question, i'm having more problems.

I have a telephony table

ID | Date | Grade
1 07/19/2010 Grade 1
2 07/19/2010 Grade 1
3 07/20/2010 Grade 1
4 07/20/2010 Grade 2
5 07/21/2010 Grade 3

I also have a Grade table

ID | Name
1 Grade 1
2 Grade 2
3 Grade 3
4 Grade 4
5 Grade 5
6 Grade 6
7 Grade 7
8 Grade 8
9 Grade 9
10 Grade 10
11 Grade 11
12 Grade 12

I use the following query to get the COUNT of every grade in the telephony table, it works great.

SELECT grade.ID, Count(telephony.Grade) AS Total
FROM grade LEFT JOIN telephony ON grade.ID=telephony.Grade
GROUP BY grade.ID
ORDER BY 1;

This returns

ID | Total
1 3
2 1
3 1
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0

However, what i'm trying to do is the following:

Group by date and only return results between two dates

SELECT telephony.Date, grade.ID, Count(telephony.Grade) AS Total
FROM grade LEFT JOIN telephony ON grade.ID=telephony.Grade
WHERE telephony.Date BETWEEN #07/19/2010# AND #07/23/2010#
GROUP BY telephony.Date, grade.ID
ORDER BY 1;

I'm getting the following

Date | ID | Total
07/19/2010 1 2
07/20/2010 1 1
07/20/2010 2 1
07/21/2010 3 1

It's not returning all the grades with 0 entries between the two dates, only the entries that exist for those dates. What i'm looking for is something like this:

Date | ID | Total
07/19/2010 1 2
07/19/2010 2 0
07/19/2010 3 0
07/19/2010 4 0
07/19/2010 5 0
07/19/2010 6 0
07/19/2010 7 0
07/19/2010 8 0
07/19/2010 9 0
07/19/2010 10 0
07/19/2010 11 0
07/19/2010 12 0
07/20/2010 1 1
07/20/2010 2 1
07/20/2010 3 0
07/20/2010 4 0
07/20/2010 5 0
07/20/2010 6 0
07/20/2010 7 0
07/20/2010 8 0
07/20/2010 9 0
07/20/2010 10 0
07/20/2010 11 0
07/20/2010 12 0
07/21/2010 1 2
07/21/2010 2 0
07/21/2010 3 1
07/21/2010 4 0
07/21/2010 5 0
07/21/2010 6 0
07/21/2010 7 0
07/21/2010 8 0
07/21/2010 9 0
07/21/2010 10 0
07/21/2010 11 0
07/21/2010 12 0
07/22/2010 1 2
07/22/2010 2 0
07/22/2010 3 0
07/22/2010 4 0
07/22/2010 5 0
07/22/2010 6 0
07/22/2010 7 0
07/22/2010 8 0
07/22/2010 9 0
07/22/2010 10 0
07/22/2010 11 0
07/22/2010 12 0
07/23/2010 1 2
07/23/2010 2 0
07/23/2010 3 0
07/23/2010 4 0
07/23/2010 5 0
07/23/2010 6 0
07/23/2010 7 0
07/23/2010 8 0
07/23/2010 9 0
07/23/2010 10 0
07/23/2010 11 0
07/23/2010 12 0

I hope someone can help. I'm using Microsoft Access 2003.

Cheers

A: 

Try this:

SELECT grade.ID, Count(telephony.Grade) AS Total
FROM grade LEFT JOIN telephony ON grade.ID=telephony.Grade
GROUP BY grade.ID
HAVING COUNT(telephony.Grade) > 0
ORDER BY grade.ID;
eKek0
A: 

That's completely different. You want a range of individual dates joined with your first table, and the between clause isn't going to do that for you.

I think you'll need a table with all the dates you want, say from 1/1/2010 to 12/31/2010, or whatever range you need to support. One column, 365 or however many rows with one date value each.

then join that table with the ones with the dates and grades, and limit by your date range, then do the aggregation to count.

Take it one step at a time and it will be easier to figure out.

Beth
+1  A: 

Create a separate query on telephony which uses your BETWEEN #07/19/2010# AND #07/23/2010# constraint.

qryTelephonyDateRange:

SELECT *
FROM telephony
WHERE [Date] BETWEEN #07/19/2010# AND #07/23/2010#;

Then, in your original query, use:

LEFT JOIN qryTelephonyDateRange ON grade.ID=qryTelephonyDateRange.Grade

instead of

LEFT JOIN telephony ON grade.ID=telephony.Grade

You could use a subquery instead of a separate named query for qryTelephonyDateRange.

Note Date is a reserved word, so I bracketed the name to avoid ambiguity ... Access' database engine will understand it is supposed to be looking for a field named Date instead of the VBA Date() function. However, if it were my project, I would rename the field to avoid ambiguity ... name it something like tDate.

Update: You asked to see a subquery approach. Try this:

SELECT g.ID, t.[Date], Count(t.Grade) AS Total
FROM
    grade AS g
    LEFT JOIN (
        SELECT Grade, [Date]
        FROM telephony
        WHERE [Date] BETWEEN #07/19/2010# AND #07/23/2010#
        ) AS t
    ON g.ID=t.Grade
GROUP BY g.ID, t.[Date]
ORDER BY 1, 2;
HansUp
Could you explain how I would use a subquery instead? Thanks
Richard L
Tht works great, however I would like to group by t.Date as well as g.ID. When I add this in it still only returns dates with a grade value. Any ideas? Thanks for all your help.
Richard L
I revised the example query. See if that's what you want.
HansUp
Cheers, I really appreciate it and i'm almost there. When a grade isnt found it's reported as 0 but only once. It isnt reported as 0 for each date. Final question I promise!
Richard L
A: 

The way I got it to work was to:

  1. Create a table named Dates with a single primary key date/time field named MyDate (I'm with HansUp on not using reserved words like "Date" for field names).
  2. Fill the table with the date values I wanted (7/19/2010 to 7/23/2010, as in your example).
  3. Write a query with the following SQL statement

    SELECT x.MyDate AS [Date], x.ID, Count(t.ID) AS Total FROM (SELECT Dates.MyDate, Grade.ID FROM Dates, Grade) AS x LEFT JOIN Telephony AS t ON (x.MyDate = t.Date) AND (x.ID = t.Grade) GROUP BY x.MyDate, x.ID;

That should get the results you asked for.

The subquery statement in the SQL creates a cross-join to get you every combination of date in the Dates table and grade in the Grade table.

(SELECT Dates.MyDate, Grade.ID FROM Dates, Grade)  AS x

Once you have that, then it's just an outer join to the Telephony table to do the rest.

Forester93