I need to work out how many different instances occur on a different day, from many different ranges. Probably best to explain it with an example.
18-JAN-09 to 21-JAN-09
19-JAN09 to 20-JAN-09
20-JAN-09 to 20-JAN-09
Using the three examples above, I need it to collect this information and display something a little like...
18th Jan: 1
19th Jan: 2
20th Jan: 3
21st Jan: 1
... I'll be grabbing the information from an Oracle database fwiw (hence the format above ^) and there will be hundreds, maybe thousands of records, so my lame attempt to do all sorts of loops and if statements would take forever to run.
Is there any fairly simple and efficient way of doing this? I'm really not too sure where to start unfortunately...
Thanks
Either your DB engine or your PHP code is going to have to loop over the date range.
Here's some PHP code to do the summation. The day counts are stored by year-month
to avoid having a huge array for a wide date range.
<?php
// Get the date ranges from the database, hardcoded for example
$dateRanges[0][0] = mktime(0, 0, 0, 1, 18, 2009);
$dateRanges[0][1] = mktime(0, 0, 0, 1, 21, 2009);
$dateRanges[1][0] = mktime(0, 0, 0, 1, 19, 2009);
$dateRanges[1][1] = mktime(0, 0, 0, 1, 20, 2009);
$dateRanges[2][0] = mktime(0, 0, 0, 1, 20, 2009);
$dateRanges[2][1] = mktime(0, 0, 0, 1, 20, 2009);
for ($rangeIndex = 0; $rangeIndex < sizeof($dateRanges); $rangeIndex++)
{
$startDate = $dateRanges[$rangeIndex][0];
$endDate = $dateRanges[$rangeIndex][1];
// Add 60 x 60 x 24 = 86400 seconds for each day
for ($thisDate = $startDate; $thisDate <= $endDate; $thisDate += 86400)
{
$yearMonth = date("Y-m", $thisDate);
$day = date("d", $thisDate);
// Store the count by year-month, then by day
$months[$yearMonth][$day]++;
}
}
foreach ($months as $yearMonth => $dayCounts)
{
foreach ($dayCounts as $dayNumber => $dayCount)
{
echo $yearMonth . "-" . $dayNumber . ": " . $dayCount . "<br>";
}
}
?>
You could use the method described in another SO:
SQL> WITH DATA AS (
2 SELECT to_date('18-JAN-09', 'dd-mon-rr') begin_date,
3 to_date('21-JAN-09', 'dd-mon-rr') end_date FROM dual UNION ALL
4 SELECT to_date('19-JAN-09', 'dd-mon-rr'),
5 to_date('20-JAN-09', 'dd-mon-rr') FROM dual UNION ALL
6 SELECT to_date('20-JAN-09', 'dd-mon-rr'),
7 to_date('20-JAN-09', 'dd-mon-rr') FROM dual
8 ),calendar AS (
9 SELECT to_date(:begin_date, 'dd-mon-rr') + ROWNUM - 1 c_date
10 FROM dual
11 CONNECT BY LEVEL <= to_date(:end_date, 'dd-mon-rr')
12 - to_date(:begin_date, 'dd-mon-rr') + 1
13 )
14 SELECT c.c_date, COUNT(d.begin_date)
15 FROM calendar c
16 LEFT JOIN DATA d ON c.c_date BETWEEN d.begin_date AND d.end_date
17 GROUP BY c.c_date
18 ORDER BY c.c_date;
C_DATE COUNT(D.BEGIN_DATE)
----------- -------------------
18/01/2009 1
19/01/2009 2
20/01/2009 3
21/01/2009 1
You need a table with one row for each day
test_calendar:
Day
16.01.2009
17.01.2009
18.01.2009
19.01.2009
20.01.2009
21.01.2009
22.01.2009
23.01.2009
24.01.2009
25.01.2009
26.01.2009
table test contains bagin and finish of inctance:
DFROM DTILL
18.01.2009 21.01.2009
19.01.2009 20.01.2009
20.01.2009 20.01.2009
Here is a query you need:
select day, (select count(1)
from test where dfrom<=t.day and dtill>=t.day) from test_calendar t
where day>to_date('15.01.2009','DD.MM.YYYY')
order by day
Huge thanks for the solutions guys - managed to get it working using some of the SQL from above and also bits of PHP from the second solution.
Really appreciate it, cheers :)