Working with date ranges in PHP/Oracle

烂漫一生 提交于 2019-12-24 10:56:00

问题


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


回答1:


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>";
  }
}

?>



回答2:


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



回答3:


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



回答4:


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 :)



来源:https://stackoverflow.com/questions/1005952/working-with-date-ranges-in-php-oracle

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!