in reply to Selecting and ordering data over multiple date ranges

You basically have data that you want to divide into buckets, with aggregate calculations performed on each bucket. One way to do this is to use a separate table to define the buckets, then JOIN against it to determine which bucket a date goes into, and GROUP BY the bucket so that aggregate calculations apply to the bucket.

Consider a table "bucket", which looks like:

+--------+------------+------------+ | name | begin | end | +--------+------------+------------+ | Jan | 2003-01-01 | 2003-01-31 | +--------+------------+------------+ | ... | +--------+------------+------------+ | Dec | 2003-12-01 | 2003-12-30 | +--------+------------+------------+
Given this, you then issue a query like
SELECT contacts.state, bucket.name, count(*) FROM contacts, bucket WHERE contacts.indentifer BETWEEN bucket.begin AND bucket.end GROUP BY bucket.name, contacts.state ORDER BY contacts.state
This'll give you a set of (state, month, count) tuples that you might need to massage a bit before emitting as an HTML table. You may find it convenient to extend the query to use an outer join so that you'll get tuples for months with no contact events.

I haven't tested the query, but I do something similar in another context to divide data into buckets by date.

The nice thing about this approach is that you can reload the bucket table with other data to get different groupings.

+--------+------------+------------+ | name | begin | end | +--------+------------+------------+ | 1Q03 | 2003-01-01 | 2003-03-31 | +--------+------------+------------+ | ... | +--------+------------+------------+ | 4Q03 | 2003-10-01 | 2003-12-30 | +--------+------------+------------+
will give you a breakdown by quarters, without changing the query.