I want to use a chart on some of my data and generate the values based on selected dates (with a date picker). I've stolen most of the stuff on the web and might have only a simple questions.
Here is the Idiorm query:
if (isset($_GET['start']) AND isset($_GET['end'])) {
$start = $_GET['start'];
$end = $_GET['end'];
$data = array();
// Select the results with Idiorm
$results = ORM::for_table('tbl_data')
->where_gte('date', $start)
->where_lte('date', $end)
->order_by_desc('date')
->find_array();
// Build a new array with the data
foreach ($results as $key => $value) {
$data[$key]['label'] = $value['date'];
$data[$key]['value'] = $value['rev'];
}
echo json_encode($data);
}
The $start and $end are from my datepicker and in yyyy-mm-dd format. The only thing I don't know how to do is how to change the ->where_gte statement. As you can see it's querying the db for the field date. In my db I have three fields, year, month and day.
Is there a way to combing the three fields year, month and day into one expression i.e. maybe ->where_gte('year'&'month'&'day', $start)???
I tried searching and searching but maybe have the wrong keywords or to less knowledge.
Thanks in advance for any help!
Since you have three fields in the DB, you need three where_gte clauses:
...
->where_gte('year', substr($start, 0, 4) // or most suitable date_format
->where_gte('month', substr($start, 5, 2) // or most suitable date_format
...
Hope it helps.
You can manage date format using MySql DATE_FORMAT() Function. E. G.:
// Select the results with Idiorm
$results = ORM::for_table('tbl_data')
->where_gte('date', "DATE_FORMAT($start, '%Y-%m-%d')")
->where_lte('date', "DATE_FORMAT($end, '%Y-%m-%d')")
->order_by_desc('date')
->find_array();
Related
I asked a question yesterday in adding together datetime intervals and was pointed to this thread - How we can add two date intervals in PHP
This is great and makes sense. However, when I try to do what the submitted answer says in a foreach loop, I'm ending up with an incorrect result.
This is a function I have made that gets all the clock in times and out times of staff, they are stored in the db and are created using PHP's date(H:i:s).
My function gets all the in and out times of any given employee, and my reporting feature I'm working on needs to display the total amount of hours they have worked.
I tried to achieve this by converting the times to datetime objects and using ->diff to get the intervals and thus calculating that days hours, I am then trying use a foreach loop to add the intervals together thus giving me a sum total of the hours worked in any given date range.
The whole function together is this:
function getTotalHours($staff_id,$from_date,$to_date){
$sql = "SELECT * FROM oc_staff_times WHERE date BETWEEN '$from_date' AND '$to_date' AND staff_id = '$staff_id'";
$result = $this->conn->query($sql);
if ($result->num_rows > 0) {
while ($row = mysqli_fetch_assoc($result)) {
$data[] = $row;
}
$base_time = new DateTime('00:00');
$total = new DateTime('00:00');
foreach ($data as $time) {
$in = new DateTime($time['clock_in_time']);
$out = new DateTime($time['clock_out_time']);
$interval = $in->diff($out);
$base_time->add($interval);
}
return $total->diff($base_time)->format("%H:%I");
}
}
I was hoping to get a monthly total, however it seems I'm only getting one days total as my final result. Here is a screen shot of the UI (the total hours are crudely circled) this also shows the time stamps my function should be adding together.
You can do this in a single query instead. Use TIMEDIFF() to get the difference for each row, then convert those to seconds by using TIME_TO_SEC(), SUM() those up and put it back into time-format with SEC_TO_TIME() - all in MySQL!
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(`clock_out_time`, `clock_in_time`))))
FROM `oc_staff_times`
WHERE `staff_id` = ?
AND `date` BETWEEN ? AND ?
Making your function with a prepared statement..
function getTotalHours($staff_id, $from_date, $to_date){
$sql = "SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(`clock_out_time`, `clock_in_time`))))
FROM `oc_staff_times`
WHERE `staff_id` = ?
AND `date` BETWEEN ? AND ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("sss", $staff_id, $from_date, $to_date);
$stmt->execute();
$stmt->bind_result($totalTime);
$stmt->fetch();
$stmt->close();
return $totalTime;
}
SQL fiddle showing the query in action http://sqlfiddle.com/#!9/525b83/7
The answer from Qirel offers a nice way to do this in SQL, however if you want to understand why your code didn't work:
$base_time = new DateTime('00:00'); does not create an interval, it's a date. It means that if you add 24 hours to it and ask only the time part, it will show '00:00' because you end up the day after.
One solution would have been to declare $base_time as an interval, for example like this:
$base_time = new DateInterval('PT0S');
And at the end output directly like this:
$base_time->format("%H:%I");
What am trying is to query orders created between two dates
so i have
$maxdate = ; //timestamp value
$mindate = ; //timestamp value
$orders = Orders::find()->where(["created_at" ..]) //stuck hre
IN normal words would be
find where created_at is between $maxdate and $mindate
How do i go about this?
You may achieve your goal by this
$orders = Orders::find()->where(["between", "created_at", $mindate, $maxdate])
This is the fully reference about building various of Queries
I'm having a tracker in Laravel 4 and I was wondering, how can I get the 'most' from my table.
So want I want is to have the day that had the most visitors.
My table structure looks like this:
So, my controller looks like this:
public function index()
{
$begin = date('Y-m-01');
$end = date('Y-m-t');
$visits = Tracker::selectRaw('date, count(ip)')->groupBy('date')->whereRaw("date between '$begin' and '$end'")->get();
//get total visits per month
$get_visits = Visitor::whereRaw("date between '$begin' and '$end'")->count();
// get average visits
// transform dates to DateTime objects (we need the number of days between $begin and $end)
$begin = new \DateTime($begin);
$end = new \DateTime('now');
$diff = $end->diff($begin); // creates a DateInterval object
$days = (int)$diff->format('%a'); // %a --> days
$average_visits = $get_visits / $days;
return View::make('admin.home.index')->with('stats', $visits)
->with('get_visits', $get_visits)
->with('average_visits', $average_visits);
}
What I want as an output:
We had the most visitors on 18/06/2015 (542 visitors)
For example.
Thanks!
You can SELECT the date ORDER BY the amount of visitors DESCENDING and LIMIT by 1. This is basic mysql. How to use this in laravel, is in the documentation.
Order by desc:
->orderBy('visits', 'desc')
Limit:
->take(1)
My example query is based on a system that has a column which counts the visits(which your structure doesn't have). So let me help you with your structure.
You want to have it by date so you basically GROUP BY date:
->groupBy('date')
From this query you want to have the amount of rows that belong to that date. So you use COUNT:
->count()
This is all based on that you know stuff about queries. This is all according to the query builder.
I have a $from date and $to date with me so I want to fetch four values from the the database for days in between $from and $to and including $from and $to . If the data does not exist for a day in the database then zero must in placed as the value for the missing values.
So how would I write a query in codeigniter to make it happen and the corresponding date should be stored in the result for a particular row .
My previous solution is that I using PHP to check and set zero for missing date. But I have some new solutions and you can try
Create a table to store dates and left/right join with your table
Or create temporary table using stored procedure and join. Temporary will be auto deleted when a session is expired
Using UNION with select statement
There're many answers on StackOverflow
MySQL how to fill missing dates in range?
MySQL group by date and count including missing dates
Running total over date range - fill in the missing dates
MySQL to fill in missing dates when using GROUP BY DATE(table.timestamp) without joining on temporary table
i think you solution needs to be actually in PHP and not sure if you can get what you are looking for directly from MYSQL just by a query. As from what i understand you want to run a query, get all records that are in your defined date range and then have dates that has no records have an empty row (or with any other value you decide...).
I would actually run the same query you have for selecting rows between the daterange and use DatePeriod Class to generate an array of all days between the start and end dates.
$begin = new DateTime( '2012-08-01' );
$end = new DateTime( '2012-10-31' );
$end = $end->modify( '+1 day' );
$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval ,$end);
foreach($daterange as $date){
echo $date->format("Y-m-d") . "<br>";
}
With this we will be able to run over each day from the $from_date to the $end_date.
Next we will need to go other the rows from the DB and see on which days there are records and where no according the the daterange object we have.
Here is an approach that would work i believe, it's not the cleanest sample but some additional work on it and you can make it a bit prettier, but i think that will work for what you need.
The Database section in the code is not in Codeigniter but as it is only getting a simple query you should not have any trouble changing that.
// set the start & end dates
$from_date = '2012-09-11';
$to_date = '2012-11-11';
// create a daterange object
$begin = new DateTime($from_date);
$end = new DateTime($to_date );
$end = $end->modify( '+1 day' );
$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval ,$end);
$sth = $dbh->prepare("SELECT col1, dateCol from tb WHERE dateCol>'".$from_date."' AND dateCol<'".$to_date."' order by dateCol ");
$sth->execute();
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
$rowsByDay = array(); // will hold the rows with date keys
// loop on results to create thenew rowsByDay
foreach($rows as $key=>$row) {
$rowsByDay[strtotime($row['dateCol'])][] = $row; // add the row to the new rows array with a timestamp key
}
// loop of the daterange elements and fill the rows array
foreach($daterange as $date){
if(!isset($rowsByDay[strtotime($date->format("Y-m-d"))])) // if element does not exists - meaning no record for a specific day
{
$rowsByDay[strtotime($date->format("Y-m-d"))] = array(); // add an empty arra (or anything else)
}
}
// sort the rowsByDay array so they all are arrange by day from start day to end day
ksort($rowsByDay);
// just for showing what we get at the end for rowsByDay array
foreach ($rowsByDay as $k=>$v) {
echo date('Y-m-d',$k);
var_dump($v);
echo '<hr/>';
}
Hope this gets you on the right way...
Hope this helps,
$this->db->where('date_column >= ',$date_given_start);
$this->db->where('date_column <= ',$date_given_end);
$this->db->get('TABLE_NAME')->result();
// if column is datetime
$this->db->where('DATE(date_column) >= ',$date_given_start);
$this->db->where('DATE(date_column) <= ',$date_given_end);
$this->db->get('TABLE_NAME')->result();
I have a date returned from an sql query (a datetime type field) and want to compare it to today's date in PHP. I have consulted php manual and there are many ways to do it. I finally came up with a solution comparing strings, but I would like to know if there are either any 'better' (best practice), cleaner or faster ways to do it. This is my solution:
// $sql_returned_date='2008-10-17 11:20:04'
$today = new DateTime("now");
$f_today=$today->format('Y-m-d'); //formated today = '2011-03-09'
$sql_date=substr($sql_returned_date,0,9); //I get substring '2008-10-17'
if($f_today==$sql_date)
{
echo "yes,it's today";
}else{
echo "no, it's not";
}
thanks
Seriously guys?
//$mysql_date_string= '2013-09-20' OR '2013-09-20 12:30:23', for example
$my_date = new DateTime($mysql_date_string);
if($my_date->format('Y-m-d') == date('Y-m-d')) {
//it's today, let's make ginger snaps
}
You could factor this into the data returned from your database query:
SELECT `DateOnDB`,
DATE(`DateOnDB`) = DATE(CURDATE()) AS isToday
FROM `dbTable`
and simply use PHP to test the value of the isToday column
Excuse me for being a question-digger, but I was trying to achieve the same thing, and I found a simple solution - if you want to select only rows with today's date you can do :
WHERE DATE(datetime_column)=CURDATE()
in your mySQL query syntax.
You'd have three solutions :
Working with strings, like you are doing ; which seems like a solution that works ; even if it doesn't feel clean.
Working with timestamps, using strtotime() and time() ; which is a bad idea : UNIX Timestamps only work for dates that are greater than 1970 and lower than 2038
Working with DateTime everywhere ; which would both work and feel clean.
If I need to make any calculation on the PHP-side, I would probably go with the third solution -- but the first one would be OK in most cases, I suppose.
As a sidenote : instead of formating your date to Y-m-d, you could check if it's :
Greater of equal than today
Less than tomorrow.
If SQL returned date is in this format 2011-03-09 (date format without timing),
$sqlret = "2011-03-05";
$curdate = date('Y-m-d');
echo $diff = strtotime($curdate) - strtotime($sqlret);
echo $no_diff = $diff/(60*60*24);
If the date with time like:
$sqlret = "2011-03-05 12:05:05",
Just make your current date format also like that:
$curdate = date('Y-m-d H:i:s');
If it doesn't satisfies your need, ask your question with some example.
You can use new DateTime php Object that way.
$date1 = new DateTime('2012-01-21');
$date2 = new DateTime ( 'now');
$interval = $date1->diff($date2);
if( $interval->format('%R%a ') == 0){
echo 'it s today';
}
I'd do that:
# SQL
SELECT DATE_FORMAT(date_col, "%Y-%m-%d") AS created_at FROM table
# PHP
if ( date('Y-m-d') == $sql_date ) { // assuming $sql_date is SQL's created_at
echo 'today';
}
$time = //your timestamp
$start = mktime(0,0,0,date("j"),date("n"),date("Y"));
$end = mktime(23,59,0,date("j"),date("n"),date("Y"));
if($time > $start && $time < $end){
//is today
}