views:

96

answers:

1

Hi

I'm about to generate some statistics based on the values of a MySQL table. I would like to generate some numbers foreach month of the year and foreach day of the month.

I could of course do all this manually but that doesn't seem like a good approach :) So anybody who has some ideas on how i generate these statistics.

OBS. I would like to get all month of the year even if there isn't any MySQL record for a given month.

BONUS: I got a little bonus question. The table which provides the data for the stats will get about 1000 records per week. I my head that seems like a bad approach over time. Anyone who has a suggestion for a better approach is welcomed. I've thought about creating CSV files instead.

In advance thanks a lot. It's appreciated!

EDIT: As asked for

+---------------+------------+------+-----+-------------------+----------------+
| Field         | Type       | Null | Key | Default           | Extra          |
+---------------+------------+------+-----+-------------------+----------------+
| id            | int(11)    | NO   | PRI | NULL              | auto_increment |
| member_id     | int(4)     | NO   |     | 0                 |                |
| status        | tinyint(1) | NO   |     | 0                 |                |
| timestamp     | timestamp  | NO   |     | CURRENT_TIMESTAMP |                |
+---------------+------------+------+-----+-------------------+----------------+
A: 

Something like this?

select count(status) as total, year(timestamp) as yr, month(timestamp) as mnth  from mytable  group by yr,mnth

As to your bonus question, 1000 records a week is not that much. How would switching to a CSV file help? You would still be getting 1000 records per week.

edit

select count(status) as total, year(timestamp) as yr, month(timestamp) as mnth, day(timestamp) as dy  from mytable  group by yr,mnth,dy

Edit 2

select count(status) as total, year(timestamp) as yr, month(timestamp) as mnth, day(timestamp) as dy, to_days(timestamp) daynum  from mytable  group by yr,mnth,dy

I've added a to_days field that would help you spot missing days as you scan through the results, daynum should be sequential.

Edit 3

OK I've had a go at it but it is untested and bear in mind PHP is my 4th or 5th language. I'm pretty sure some of the gurus round here could do it a lot more elegantly.

<?php

$con = mysql_connect("myhost","myusername","mypassword");
if (!$con)
  {
  die('Could not connect: ' . mysql_error());
  }

mysql_select_db("mydatabase", $con);

$result = mysql_query("select count(status) as total, year(timestamp) as yr, month(timestamp) as mnth, day(timestamp) as dy, to_days(timestamp) as daynum  from mytable  group by yr,mnth,dy");

$row = mysql_fetch_array($result);
$counter=$row['daynum']-$row['day']+1; // set up the daynum counter an initiaise to the first day of the month "-$row['day']+1"

//print out any blank rows at the beginning of the month
for ($i = $counter; $i <=$row['daynum'] ; $i++) {
    echo "A blank row";
}

// start to loop through the result set
$finished=false;
do {

if($counter=$row['daynum']){  // if the daynumber of the row matches the counter then  print the row and get the next row 

    echo "an output row from db".$row('dy')."-".$row('mnth')."-".$row('yr')."-----".$row('total');
    $lastday=$row['dy'];
    $lastmonth=$row['mnth'];
    $lastyear=$row['yr'];   

    $row = mysql_fetch_array($result);
    if (!$row) finished=true;

} else { // if the counter if not equal it must be less than $row['daynum'] so print blank rows and increment counter until it matches the current row.

    $mytime = $counter*24*60*60;   //convert days to seconds, because PHP doesn't seem to have a from_days function
    $mydate = strftime("%Y-%m-%d", $mytime); //convert seconds to date
    echo $mydate."a blank row"

    $counter=$counter+1;
    }

} while ( ! finished);


// print out any blank days at the end of the month
$daysinmonth = cal_days_in_month(CAL_GREGORIAN, $lastmnth, $lastyear);

for ($i = ($lastday+1); $i <=$daysinmonth; $i++) {
    echo $i."-".$lastmonth."-".$lastyear." ---  A blank row";
}



mysql_close($con);

?>
Jaydee
This doesn't address the need for missing months, nor days of the month
Cez
As Cez says this doesn't really fix my problem. The solution you suggest is in fact very much like the one I'm using at the moment.
nickifrandsen
The bonus question: I just had a brief idea that if I group records by month for example in a CSV file. Overtime I could just call the CSV file I need instead of the whole table?I might be a bad idea. Like I said it's just a thought I'm having.
nickifrandsen
With the missing day, a quick cludge is to create a system member_id and add a record each day for that member_id, then subtract 1 from the total returned by the query. You would need to create a record for each day in the past of course, but from then on it is just one additional record per day. To be perfectly honest I'd probably look for the missing day programatically when scanning the query results.
Jaydee
I can see that working, though I don't see it as a fairly great approach. It should be possible to let PHP handle the missing dates so I avoid "fake" records in the table.
nickifrandsen
On the bonus question: if you are using the database anyway, then I'd use it for the log, the record size is pretty small even 10 years records aren't going to take up that much space 52 x 1000 = 52,000 recordss per year. Times record size say 40 bytes = 2Mb per year? If you are pressed for space I'd archive older data, possibly to text files (CSV or otherwise).
Jaydee
That in fact the approach I'm using at the moment. So this confirms me that I'll stay with that approach for the moment.
nickifrandsen
The to_days() function I added above should help you identify missing days, there are two things you would need to do: 1. maintian a counter so that you know what the daynumber should be (if the record doesn't match you have a missing day) 2. Initialise the counter to the day number of the day you want to start at eg if you want to start on 1st of month and 1st result is 5th of month then subtract 4 from that daynumber as teh start value of the counter then start scanning the results.
Jaydee
Is there any way you can try to illustrate your point with the php snippets you suggests.
nickifrandsen
I'm more java than PHP but when I have time I'll try to put something together
Jaydee
Thanks a lot a really appreciate it :)
nickifrandsen
Ok you can have a look at that, hopefully you can see what I mean even if it doesn't work as it is supposed to.
Jaydee
Cool. Thx a lot for taking your time to illustrate it for me. I'll try to adjust it a bit to make it fit and let you know if I can get to work properly for my use.I really appreciate the effort you have put in this.
nickifrandsen