Symfony: DQL select between date - php

I'm trying to select from my SQLite table all the rows in selected months and sum the value in "total" column.
Here is my example table:
| ID | DATE | TOTAL |
| 1 | 22-11-2017 | 700 |
| 2 | 26-11-2017 | 100 |
| 3 | 28-11-2017 | 150 |
| 4 | 30-11-2017 | 50 |
Here is the dql function
public function getDataByMonth($repo, $year, $month)
{
date = new \DateTime("{$year}-{$month}-01 00:00");
$dateEnd = new \DateTime("{$year}-{$month}-31 23:59");
$query = $qb->where('b.date BETWEEN :start AND :end')
->setParameter('start', $date->format('d-m-Y H:i'))
->setParameter('end', $dateEnd->format('d-m-Y H:i'))
->select('SUM(b.total) as totals');
}
Even if the query goes, when I set $monthvariable to October (so 10) the query return 1000instead of NULL.
I'm calling the function using
$earnings = $this->getDoctrine()->getManager()->getRepository(Invoices::class);
$this->getDataByMonth($earnings,date("Y"), strftime("%m", strtotime("-1 months")));
What I'm doing wrong?
I need to select the right rows relating to the selected month.

maybe you should try sth like this, had similar problem and it worked:
->add('where', $qb->expr()->between(
'e.datetimefield',
':from',
':to'
))
it's database software independent, should work with most databases, more info in doctrine documentation:
http://docs.doctrine-project.org/en/latest/reference/query-builder.html#the-expr-class
and also don't format datetime object, ex:
$from = new \DateTime();
->setParameter('from', $from);

SQLite does not have a storage class set aside for storing dates
and/or times. Instead, the built-in Date And Time Functions of SQLite
are capable of storing dates and times as TEXT, REAL, or INTEGER
values
--https://sqlite.org/datatype3.html
So I don't think you can use BETWEEN.
I had similar issue with SQLite I ended up using timestamp

Symfony 3 ?
$date = new \DateTime("{$year}-{$month}-01 00:00");
$dateEnd = new \DateTime("{$year}-{$month}-31 23:59");
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery("SELECT SUM(p.total) FROM AppBundle:Invoices p WHERE p.date >= :dateFirstDay and p.date <= :dateLastDay")
->setParameter('dateFirstDay',$date->format('d-m-Y H:i'))
->setParameter('dateLastDay',$dateEnd->format('d-m-Y H:i'));

Related

Selecting entries by date and by time seperately with MySQL

I have this query that selects every appointment with status Pending. Works well. The problem with this query it will also select appointments that are pending in the past. I only want to display those that are either today at a later hour than current_time or simply at a later date. Time and date are in a different column. In the example below only the second and third row should be returned. I'm giving you the full query as it is used and working in my app right now. How can this be achieved?
user_schedule table
id | customer_id | date | time | cleaning_status
1 | 345 | 2020-06-09 | 08:00:00 | Pending
2 | 768 | 2020-06-09 | 19:00:00 | Pending
3 | 913 | 2020-06-11 | 07:00:00 | Pending
PHP
if(!empty($_POST)){
//variables
$current_time ='16:00:00';
$current_date ='2020-06-09';
$my_city ='Miami';
$sstatus_o = 'Pending';
//query
$data = $conn->prepare("select *,us.id as orderid,us.customer_id
as ownerId from user_schedule us
left join users u
on us.customer_id=u.id
LEFT JOIN user_avatar ua
ON us.customer_id=ua.user_id
and ua.last_update = (select
max(last_update)
from user_avatar ua1 where
ua.user_id=ua1.user_id)
left join user_address uad
on us.customer_id=uad.user_id
where (uad.city LIKE ?) AND
us.cleaning_status=? ORDER BY us.id DESC");
$data->bind_param('ss',$my_city,$sstatus_o);
$data->execute();
$result_data = $data->get_result();
}
You can add another constraint to your query that checks whether the timestamp formed from your date and time values is greater than your $current_date and $current_time values i.e.
WHERE uad.city LIKE ?
AND us.cleaning_status = ?
AND TIMESTAMP(us.date, us.time) > TIMESTAMP(?, ?)
and then add the $current_date and $current_time variables to the bind_param i.e.
$data->bind_param('ssss', $my_city, $sstatus_o, $current_date, $current_time);

How to Get Where 'Column + 7 Days' >= NOW in PHP

I have a problem. Maybe this question is very stupid, but I've been searching everywhere and not getting what I want.
I will immediately delete my post, if I get the answer.
I've a table like this:
ID | Title | Date
-----------------------------
1 | AAA | 2019-03-25
2 | BBB | 2019-03-21
3 | CCC | 2019-03-23
I've tried this:
function get_all() {
$plusdays = strtotime('+7 day');
$now = date('Y-m-d H:i:s');
$this->datatables->select('*');
$this->datatables->from('atable');
$this->datatables->where('crt_date + INTERVAL 7 day >=', $now);
return $this->datatables->generate();
}
How I can show table like this:
ID | Title | Date
-----------------------------
2 | BBB | 2019-03-21
So I want to show data created on a certain date and expire if more than 7 days after the data was created. Or are there other ideas?
do I have to add the expired date column?
Thanks
Here's an SQL query that should work (and no, it's not necessarily the most elegant one):
SELECT *
FROM atable
WHERE (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(date)) >= (60 * 60 * 24 * 7);
I presume you can translate that appropriately to your PHP code. Basically, I'm getting the difference in seconds between now() and the stored date then I'm seeing if the difference is greater than or equal to seven days.
I decided to add one more column is exp_date for easier use in the future.
Code like this:
$date = time();
$date_exp = date('Y-m-d H:i:s', strtotime('+7 day', $date));
Thanks everyone!
Tip Don't use function or eval in column at where (performance problem)
In this case you must subtract $now by 7 day and
$this->datatables->where('crt_date >=', $theDateBefore7Day);

How to check given date period is between two dates in MySQL and PHP

I have a travel history of the employee. I want to check, for the particular month, whether he is in outstation (traveled outside) or in the office, to calculate number of hours in travel. Just we are maintaining the travel database, in that we entered employee name with client place traveled with travel date and returned date.
One employee have the following data:
Traveled date: '2015-08-29' (29th Aug 2015)
returned date: '2015-11-06' (6th Nov 2015)
So here, I want to check in the month of October, all employees that are out of the office. Obviously this guy should come in that category, but I could not get him.
I also tried directly in MySQL workbench, but I didn't get the result.
My original PHP code:
// $req['date_start'] = '2015-10-01'
// $req['date_end'] = '2015-10-31'
$employeeTravel = new EmployeeTravelRecord();
$TravelEntryList = $employeeTravel->Find("(travel_date between ? and ? or return_date between ? and ? )",array($req['date_start'], $req['date_end'],$req['date_start'], $req['date_end']));
$startdate = $req['date_start'];
$enddate = $req['date_end'];
foreach($TravelEntryList as $Travelentry){
$key = $Travelentry->employee;
if($startdate >= $Travelentry->travel_date)
{
$firstdate = $startdate;
}
else
$firstdate = $Travelentry->travel_date;
if($enddate <= $Travelentry->return_date )
{
$lastdate = $enddate;
}
else
$lastdate = $Travelentry->return_date;
$holidays = $this->getholidays($firstdate,$lastdate);
$totalhours = $this->getWorkingDays($firstdate,$lastdate,$holidays); //It returns in total time of outstation in hours excluding company holidays
$amount = $totalhours;
if(isset($TravelTimeArray[$key])){
$TravelTimeArray[$key] += $amount;
}else{
$TravelTimeArray[$key] = $amount;
}
}
But my input data doesn't retrieve that particular employee record, because both traveled date and returned date don't fall in my input dates.
MySQL Workbench:
SELECT * FROM employeetravelrecords where travel_date between '2015-10-01' and '2015-10-31' or return_date between '2015-10-01' and '2015-10-31';
I got only the following result:
+----+----------+---------------+----------------+----------+------------------+------------------+----------------+
| id | employee | type | project | place | travel date | return date | details |
+----+----------+---------------+----------------+----------+------------------+------------------+----------------+
| 13 | 38 | International | PVMTC Training | Hongkong | 11/10/2015 13:33 | 28/11/2015 13:33 | PVMTC Training |
| 14 | 48 | International | PVMT | VIETNAM | 10/10/2015 9:28 | 1/1/2016 9:28 | PETRO |
| 17 | 57 | International | PVMT | Saudi | 10/10/2015 11:39 | 2/1/2016 11:39 | |
+----+----------+---------------+----------------+----------+------------------+------------------+----------------+
The following record didn't get retrieved by this query:
+---+----+---------------+------+-----+-----------------+-----------------+-----------------+
| 7 | 22 | International | MOHO | XYZ | 29/8/2015 18:00 | 6/11/2015 18:00 | FOR DDS review |
+---+----+---------------+------+-----+-----------------+-----------------+-----------------+
SELECT * FROM employeetravelrecords
WHERE
return_date >= '2015-10-01' /* start parameter */
and travel_date <= '2015-10-31' /* end parameter */
The logic seems a little mind-bending at first and I've even reordered the comparisons a little from my original comment above. Think of it this way: you need to return after the start of the range and leave before the end of the range in order to have an overlap.
For a longer explanation and discussion you might find this page useful: TestIfDateRangesOverlap
SELECT '2015-08-29' < '2015-10-31' AND '2015-11-06' >= '2015-10-01' on_leave;
+----------+
| on_leave |
+----------+
| 1 |
+----------+
You can use between for get data between two dates. Here is the working example.
Here is my table structure :
Table User
user_id user_name created_date modified_date
1 lalji nakum 2016-01-28 17:07:06 2016-03-31 00:00:00
2 admin 2016-01-28 17:25:38 2016-02-29 00:00:00
And here is my mysql query :
Query
SELECT * FROM `user` WHERE created_date between '2015-12-01' and '2016-12-31' or modified_date between '2015-12-01' and '2016-12-31'
Result of above query :
Result
user_id user_name created_date modified_date
1 lalji nakum 2016-01-28 17:07:06 2016-03-31 00:00:00
2 admin 2016-01-28 17:25:38 2016-02-29 00:00:00
You want to find all those people who are not available for the complete duration say between T1 & T2 (and T2 > T1). The query you used will only give users whose start date and return date both lie between the given interval which is not the required output.
So to get the desired output you need to check for all employees who have started their journey on or before T1 and return date is on or after T2 (thus unavailable for complete interval [T1, T2]). So the query you can use is:
SELECT * FROM employeetravelrecords where travel_date <= '2015-10-01' and return_date >= '2015-10-31';
If you want employees who are even partially not available between the given duration then we need employees who started their travel before T1 and have any return date later than T1 (thus making them atleast unavailable for a part of the given interval):
SELECT * FROM employeetravelrecords where travel_date <= '2015-10-01' and return_date > '2015-10-01';

PHP MySQL, sum of rows based on datetime row

I'm trying to sum number of persons based on datetime rows.
this is how my table looks like:
id | date | person |
---+-------------------+--------+
1 |2013-12-26 00:00:00| 3 |
---+-------------------+--------+
2 |2013-12-26 00:00:00| 2 |
---+-------------------+--------+
3 |2013-12-26 00:00:00| 3 |
---+-------------------+--------+
4 |2018-10-21 00:00:00| 3 |
---+-------------------+--------+
What i want my query to do is: Sum all persons based on date. But i think my problem is not query it self (or maybe it is), but the datetime. I have something like
$date = "26.12.2013";
$date = strtotime(date("d.m.Y", strtotime($date)));
$date = date("Y-m-d", $date);
$query= "SELECT '$date', SUM('person') totalperson FROM table_name WHERE date='$date' GROUP BY '$date'";
but the number returned is 2016 and expected is 8 :)
I hope my question is clear enough.
SUM(`person`)
Use backticks for column name,you are suming a string
What db engine do you use?
Anyway, this should work:
$date = "2013-12-26 00:00:00";
$query = "
SELECT date, SUM(person) totalperson
FROM table_name WHERE date='$date'
GROUP BY date
";
SELECT
date,
SUM(person) totalperson
FROM table_name
WHERE DATE(date) = '$date'
GROUP BY date
Use DATE() function
you are providing date string in date time column

Return how many records created, closed, and open for each day in a time period

I have a table that stores creation and closure dates. What I'm trying to do is run a query that gives me in a given time period, for each day, how many records were created, how many were closed, and how many were open. Table structure:
+------------------------+
| Field | Structure |
+------------+-----------+
| id | int |
| start_date | datetime |
| close_date | datetime |
+------------+-----------+
The first two queries are not a problem - what I'm working with right now is this:
SELECT COUNT(*), start_date FROM dates
WHERE start_date BETWEEN 'start' AND 'end'
GROUP BY start_date
ORDER BY start_date ASC
SELECT COUNT(*), close_date FROM dates
WHERE close_date BETWEEN 'start' AND 'end'
GROUP BY close_date
ORDER BY close_date ASC
The third query is an issue - I can get it to give me how many were open on a day where that day exists in the table, but what I haven't figured out is how to make it write out a row for every day in the year and give me the count for that day.
That's the first problem.
The second is that I want to get it to give me a result like this, and I can't figure out how to do it - searching around here has given me a few false starts, but nothing solid.
+------------+--------+--------+--------+
| Date | Opened | Closed | Active |
+------------+--------+--------+--------+
| 2012-05-06 | 3 | 2 | 7 |
| 2012-05-07 | 2 | 0 | 9 |
| 2012-05-08 | 0 | 0 | 9 |
| 2012-05-09 | 0 | 3 | 6 |
+------------+--------+--------+--------+
I'm entirely willing to run separate queries if necessary and handle all of it in code instead of db if I have to - I'm fairly sure I can write all of the query data from the individual queries to a single array and just loop through that to build the report, but I'd really prefer not. Any suggestions?
This query is tricky because you want the status list for every date in range.
In this query the dates are generated in join query.
For that i used the same table assuming it has
count of records >= the number of dates between daterange
id-s must be consecutive up to number of dates between daterange
You can replace that with your own dates list generation subquery.
set #start :='2012-05-06';
set #end :='2012-05-09';
select cdate as Date
, sum(start_date = cdate) Opened
, sum(close_date = cdate or close_date is null) Closed
, sum(start_date <= cdate and (close_date>cdate or close_date is null)) Active
from dates
join (select date(#start + interval id-1 day) cdate from dates where id <= to_days(#end)-to_days(#start)+1) d
on start_date <= cdate and (close_date>=cdate or close_date is null)
where start_date <= #end
and (close_date >= #start or close_date is null)
group by cdate
order by cdate
;
Creating an aggregate table like this is really difficult with just SQL statements. You will need to use subqueries, UNION statements and/or possibly a stored procedure to get the logic spot on so that it displays the table as you present it.
The two queries that you have already are much faster than the approach I mentioned above. A PHP array will definitely help there to get what you need.
So:
Step 1
SELECT COUNT(*) AS active_before_start
WHERE start_date < 'start'
AND close_date IS NULL
Get that number and store it in $active_before_start.
Step 2
SELECT COUNT(*) AS total_opened, start_date FROM dates
WHERE start_date BETWEEN 'start' AND 'end'
GROUP BY start_date
ORDER BY start_date ASC
Put these results in an array
foreach ($results as $result)
{
$key = $result->start_date;
$final_table[$key]['date'] = $key;
$final_table[$key]['opened'] = $result->total_opened;
}
Step 3
SELECT COUNT(*) AS total_closed, close_date FROM dates
WHERE close_date BETWEEN 'start' AND 'end'
GROUP BY close_date
ORDER BY close_date ASC
Again store those in the array
foreach ($results as $result)
{
$key = $result->close_date;
$final_table[$key]['date'] = $key;
$final_table[$key]['closed'] = $result->total_closed;
}
Step 4
Now you can traverse the table to manipulate the data so that it produces the result you need as such:
$results_table = array();
$active = $active_before_start;
foreach ($final_table as $key => $item)
{
$opened = (isset($item['opened']) ? $item['opened'] : 0;
$closed = (isset($item['closed']) ? $item['closed'] : 0;
$active = $active + ($opened' - $closed);
$results_table[$key]['date'] = $key;
$results_table[$key]['opened'] = $opened;
$results_table[$key]['closed'] = $closed;
$results_table[$key]['active'] = $active;
}
From then on you can always do a ksort just in case to show the sorted array results.
HTH
I can get it to give me how many were open on a day where that day exists in the table, but what I haven't figured out is how to make it write out a row for every day in the year and give me the count for that day.
I understand it as : you want to count the issue for each close date?
SELECT COUNT(*) FROM dates WHERE your_condition GROUP BY DAY_OF_YEAR(close_date)

Categories