I have a basic table with orders, which have a field thats called created_at which is in timestamp format and I want to get the avarage on how many orders have been created per day.
Found a other similar qestion about something like mine question whichI have posted below in the hope that everybody understand what im trying to do.
//not working
$q = new \yii\db\Query();
$q->from('shopping_cart');
$total = $q->average('DATEDIFF(`created_at`, CURRENT_DATE())');
I believe it is more SQL related problem than Yii2. What you need (if I have understood it correctly) is:
count number of days from the beginning to today
count all the rows
divide these number to get the average.
I have tried this and it works fine
SELECT
count(*) / (select round((unix_timestamp() - (select min(created_at) from table)) / 86400))
from table;
back to Yii2: I believe you have to build this query manually
\Yii::$app->db->createCommand()
Method average in $q->average('DATEDIFF('created_at', CURRENT_DATE())'); just adds AVG(DATEDIFF('created_at', CURRENT_DATE())) to SQL command.
As Jiri Semmler said, what you want to do is about SQL not Yii.
All you need to do is find the count of records for the period you are interested in and divide it by the number of days of that period.
It can be something like
// Define period
$timeFrom = '2018-11-30';
$timeTo = '2018-12-02';
// Number of days for the period
$days = date_diff(date_create($timeFrom), date_create($timeTo))->format("%a");
// Query count of records between dates
$q = new \yii\db\Query();
$total = $q->from('order')
->where(['between', 'created_at', $timeFrom, $timeTo])
->count();
// Find average records per day
$average = $total / $days;
If you have Order model class:
// Query count of records between dates
$total = Order::find()
->where(['between', 'created_at', $timeFrom, $timeTo])
->count();
Related
I am using CodeIgniter. I am calculating the total working hours in a day.
So what I am doing is, When user login in the system It will insert the login time in the table and is_active status will 1. Something like this
If the user log out then it will update the logout time and is_active status will 0.
If the same user login again then it will insert the new login time
Same process for logout.
I can calculate the time between two dates but in my scenario, the user can log in multiple times.
I am displaying the list of the record which is is_active status is 1.
Model
public function get_current_login(){
$this->db->select('*');
$this->db->from('tbl_employee');
$this->db->join('tbl_current_login','tbl_current_login.emp_id=tbl_employee.id');
//$this->db->where($where);
$this->db->where('is_active',1);
$query = $this->db->get();
$result = $query->result();
if($result)
{
return $result;
}
else
{
return 0;
}
}
Above code will display the list of the user where is_active status is 1.(I haven't shared the view and controller code).
Now I have to calculate the total working hours in a day.
Is I am on the right path to insert and update the login and logout time?
Is it possible to calculate using MYSQL or I have to use PHP?
MySQL supports TIMESTAMPDIFF:
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html
You can use it to give the number of hours or fractional hours between two datetimes
If you want a reasonably precise number of hours out of it, you can ask for the number of seconds between two times and divide the result by 3600
If you’re doing reports that calculate how many hours an employee worked per week or per month, group by employee and week/month and sum the hours. To reduce a date to a week or month granularity use the YEAR() function and the MONTH() or WEEK() functions
Example:
SELECT emp_id, year(login_time), month(login_time), sum(timestampdiff(second, login_time, logout_time)/3600.0)
FROM timeclock
WHERE logout_time > ‘0000-00-00’
GROUP BY
employee_id, year(login_time), month(login_time)
Substitute week in for month if you want the report weekly
Heres a report that gives the login and logout time on each date and the hours worked that day:
SELECT emp_id, year(login_time), month(login_time), day(login_time), min(login_time), max(logout_time), sum(timestampdiff(second, login_time, logout_time)/3600.0)
FROM timeclock
WHERE logout_time > ‘0000-00-00’
GROUP BY
employee_id, year(login_time), month(login_time), day(login_time)
I usually calculate the time after fetching data from database.
<?php
// Let's assume the $result is the database records result
$current_date = date('Y-m-d H:i:s');
$total_duration = 0;
foreach ($result as $row)
{
// Set logout date as current date if user still logged in
if ($row['logout_time'] === '0000-00-00 00:00:00') $row['logout_time'] = $current_date;
// You may need to group the total duration based on employee id
$total_duration += strtotime($row['logout_time']) - strtotime($row['login_time']);
}
You will get the time in second and can convert in your format.
select sum(TIMESTAMPDIFF(SECOND,login_time,logout_time)) from table_name group by date(login_time),id;
Good afternoon lads, I am trying to make a page where I can check which bosses I did today. I have two tables (table with bosses and table with boss times). Now I need to show all bosses but for each of them I only want to show the closest time when the boss is going to spawn.
The select so far looks like that:
$timePlus = strtotime($currentTime) + 60*60*2.2;
$timePlusForm = date("H:i:s", $timePlus);
$userNametoLower = strtolower($userName);
$userTableName = "".$userNametoLower."_bosses";
$currentTime = date("H:i:s", time());
"SELECT `bossTime`.`ID`, `bossTime`.`bossID`, `bossTime`.`time`, `$userTableName`.`ID`, `$userTableName`.`name`,
`$userTableName`.`zone`, `$userTableName`.`map`, `$userTableName`.`waypointCode`, `$userTableName`.`bossDone`
FROM `bossTime` LEFT JOIN `$userTableName` ON `$userTableName`.`ID` = `bossTime`.`bossID`
WHERE `bossTime`.`time` BETWEEN '$currentTime' AND '$timePlusForm'
GROUP BY `bossTime`.`bossID`
ORDER BY `bossTime`.`time` ASC";
The problem is that this select does not pick the next closest value from time table. I also tried BETWEEN and it also didn't work (some bosses got correct closest time but other got the second closest). Any idea how to solve this is welcomed.
I removed GROUP BY and changed the condition to WHERE bossTime.time >= '$currentTime' AND bossTime.time <='$timePlusForm' and for some reason it works
I'm having trouble how to implement a search functionality on a website I'm working on.
The search form has two fields, starting date and an end date which a user wants to rent a vehicle.
In the database I have two tables, one for the vehicle and another one for available dates.
Table: cars
- car_id (int)
- name (varchar)
- description (varchar)
Table: cars_availability
- car_id (int)
- date (datetime)
- status (int) // 1: available 2: booked
Each row in cars_availability represent a day that the associated car is available for rent or booked.
Problem:
If user searches for a car that is available from 5.feb.2013 to 8.feb.2013 I would like to do a query to select all cars that are available for all the days in the users selection.
My current unfinished solution:
I know I can iterate through all the days using something like this
$begin = new \DateTime( date('Y-m-d', strtotime($data['rent_start'])));
$end = new \DateTime( date('Y-m-d', strtotime($data['rent_end'])));
$end = $end->modify( '+1 day' );
$interval = \DateInterval::createFromDateString('1 day');
$period = new \DatePeriod($begin, $interval, $end);
$available_cars = array();
foreach ( $period as $dayTime ){
// query the cars and joining the cars_availabilty table
$item = DB::select('cars.*')
->from('cars')
->join('cars_availability')->on('cars_availability.item_id', '=', 'cars.item_id')
->where('items_availability.date', '=', $dayTime->format("Y-m-d H:i:s"))
->and_where('items_availability.status', '=', 1)
->execute()->as_array();
if(count($item) > 0){
if(isset($available_cars[$item[0]['item_id']])){
$available_cars[$item[0]['item_id']][] = $item[0];
}else{
$available_cars[$item[0]['item_id']] = array();
$available_cars[$item[0]['item_id']][] = $item[0];
}
}
}
After this I would have an array of vehicles that might have all the days available but I would need to do some extra math to find that out.
I want know if there is some more elegant solutions to this problem, using a better query maybe.
If you can give me any feedback on this I would be very grateful.
Thanks
This is actually a fairly sane setup to query. Personally, I'd recommend following #inhan's advice, especially if it turns out cars can be booked for smaller slices of time (hours?). However, the queries get a little bit more complicated to write, because of edge-cases (if you look around here, you should find relevant examples).
Unfortunately, I can't speak to how this fits into your framework, but the SQL can look like this:
SELECT Cars.car_id, Cars.name, Cars.description
FROM Cars
JOIN (SELECT car_id
FROM Cars_Availability
WHERE `date` >= '2013-02-05'
AND `date` < '2013-02-09'
AND status = 1
GROUP BY car_id
HAVING COUNT(*) = DATEDIFF('2013-02-09', '2013-02-05')) Available
ON Available.car_id = Cars.car_id
(Have an SQL Fiddle Example)
This query assumes that there's only one entry per day, or this breaks. Basically, it grabs every 'available' row greater-than/equal the beginning date, and less than the 'end' date (date/time/timestamps are... complicated; this article deals with SQL Server-specific problems, but the basic concepts apply), and makes sure there's one for the count of days between them. Mostly, you were looking for the HAVING clause.
Given the proper index on Cars_Availability, it may not even hit the table, making this a good performer, too.
Okay guys, this probably has an easy answer but has been stumping me for a few hours now.
I am using PHP/HTML to generate a table from a MySQL Table. In the MySQL table (TimeRecords) I have a StartTime and EndTime column. In my SELECT statement I am subtracting the EndTime from the StartTime and aliasing that as TotalHours. Here is my query thus far:
$query = "SELECT *,((EndTime - StartTime)/3600) AS TotalPeriodHours
FROM TimeRecords
WHERE Date
BETWEEN '{$CurrentYear}-{$CurrentMonth}-1'
AND '{$CurrentYear}-{$CurrentMonth}-31'
ORDER BY Date
";
I then loop that through an HTML table. So far so good. What I would like to do is to add up all of the TotalHours and put that into a separate DIV. Any ideas on 1) how to write the select statement and 2) where to call that code from the PHP/HTML?
Thanks in advance!
Try this
$query= "
SELECT ((EndTime - StartTime)/3600) AS Hours, otherFields, ...
FROM TimeRecords
WHERE
Date BETWEEN '{$CurrentYear} - {$CurrentMonth} - 1'
AND '{$CurrentYear}-{$CurrentMonth} - 31' ";
$records =mysql_query($query);
$sum= 0;
while($row=mysql_fetch_array($records))
{
echo"$row['otherFields']";
echo"$row['Hours']";
$sum+=$row['Hours'];
}
echo" Total Hours : $sum ";
Just use a single query with a Sum(). You could also manually calculate it if you're already displaying all rows. (If paginating or using LIMIT, you'll need a separate query like below.)
$query = "
SELECT Sum(((EndTime - StartTime)/3600)) AS SumTotalPeriodHours
FROM TimeRecords
WHERE
Date BETWEEN '{$CurrentYear} - {$CurrentMonth} - 1'
AND '{$CurrentYear}-{$CurrentMonth} - 31'
";
You can do this in the same query if you have a unique id using GROUP BY WITH ROLLUP
$query = "
SELECT unique_id,SUM((EndTime - StartTime)/3600) AS TotalPeriodHours
FROM TimeRecords
WHERE Date BETWEEN '{$CurrentYear}-{$CurrentMonth}-1'
AND '{$CurrentYear}-{$CurrentMonth}-31'
GROUP BY unique_id WITH ROLLUP
ORDER BY Date
";
In this instance the last result from your query with contain NULL and the overall total. If you don't have a unique ID you will need to do it in PHP as per Naveen's answer.
A few comments on your code:
Using SELECT * is not considered good practice. SELECT the columns you need.
Not all months have a day 31 so this may produce unexpected results. If you're using PHP5.3+, you can use
$date = new DateTime();
$endDate = $date->format( 'Y-m-t' );
The "t" flag here gets the last day of that month. See PHP docs for more on DateTime.
I am creating a blog post scheduling system using CodeIgniter. I want 10 posts to show up a day. There is a field in the posts table named scheduled_date which I will get the posts that are less than or equal to the current date. When an admin user adds a new record to the database, I need an SQL statement that somehow will help me COUNT the number of records with the latest date in the database. For example:
// 9 records returned for the date 2011-01-01
$numbers_of_records == 9;
if($numbers_of_records == 10){
// inserts record with `scheduled_date`='2011-01-01'
}else{
// inserts record with the date latest date +1 day
}
How would I efficiently accomplish this?
Thanks
This will do the trick. It is simple and efficient.
<?php
// It is very bad to have floating values, especially for settings
// it is good to use some sort of factory or settings class
$maxDailyPosts = (int) SettingsFactory::getSettings()->get('maxDailyPosts');
$date = '2011-01-01';
// Load # of post for data
$numberOfRecords = (int) getNumberOfPostPerDate($date);
// Figure out the interval for increment
$dayInterval = ($numberOfRecords >= $maxDailyPosts ) ? 1 : 0;
//
$query = "INSERT INTO tbl (publish_date, ...) VALUES (DATE_ADD('$date', INTERVAL $dayInterval DAY), ...)";
?>