Calculating data from one DB table with range of dates - php

I have sql function:
$sql = "SELECT date(datum_ura) as datetime,
COUNT(CASE rezultat_status_fk WHEN 5 THEN rezultat_status_fk END) AS half_lost, AVG(kvota) as average, SUM(vlozek) as vlozek,
SUM(CASE rezultat_status_fk WHEN 1 THEN vlozek * kvota WHEN 2 THEN vlozek WHEN 3 THEN 0 END) AS case_profit,
SUM(CASE rezultat_status_fk WHEN 1 THEN vlozek * kvota-vlozek WHEN 2 THEN 0 WHEN 3 THEN -vlozek END) AS profit
FROM bs_analiza
WHERE users_fk=$user_id"." group by date(datum_ura)";
The function is getting data from one table and calculates it and show results by dates. I'm trying to do a function which can sum current date result with the day before result....and so on.
I'm thinking of something like:
foreach ($items as $key => $value) {
$date = $value->datetime;
$prev_date = date('Y-m-d', strtotime($date .' -1 day'));
$prev_date = strtotime($prev_date);
$i = $key-1;
$profit_before = $items[$i]->$prev_date;
But I'm still getting the same results.

You can achieve this with selects from your intermediate result, I suggest you either create a view or use WITH.
SELECT
datetime,
(SELECT SUM(vlozek) FROM ... WHERE datetime >= t.datetime) vlozek_cumsum,
(SELECT SUM(case_profit) FROM ... WHERE datetime >= t.datetime) case_profit_cumsum,
(SELECT SUM(profit) FROM ... WHERE datetime >= t.datetime) profit_cumsum
FROM
... t
ORDER BY
datetime DESC
... is your intermediate result.
Edit (to clarify): You get your intermediate result by a select statement. So you can either
Create a view and replace ... by the name of the view or
CREATE OR REPLACE VIEW <view_name> AS <select_stmt>
Use WITH and replace all ... in the query above by the alias name.
WITH <alias_name> AS ( <select_stmt> )
SELECT
...

Related

Why mysql query between date variables is not returning a range

Foreword: I tried to find an answer to this and while there are some similarities in some of the answered questions, there were no matches.
I'm trying to generate 3 month reports but only the current date is returning a value.
<?php
// Db connect
include_once ('db.php');
global $con2;
// 3 month reports
$date_from = date("d-m-Y", strtotime(" -3 months"));
$date_to = date('d-m-Y');
// Count
$get = "select * from table1 where date between '$date_from' and '$date_to'";
$get_connect = mysqli_query($con2, $get);
$get_rows = mysqli_num_rows($get_connect);
// Display data
echo $get_rows;
?>
Additional info.
The dates already stored in the date column of table1 are in exactly the same format as the variables eg: 10-10-2017
The entires which are from today are being displayed but nothing else is. Is this because PHP can only read up till the first - dash?
Using dd-mm-yyyy strings as dates simply will not work correctly with "between"
select
*
from (
select '10-10-2017' as 'date' union all
select '11-11-2017' as 'date' union all
select '10-10-1989' as 'date' union all
select '10-10-2020' as 'date' union all
select '10-10-3017' as 'date'
) table1
where `date` between '10-10-2017' and '11-11-2017'
order by `date`
date
1 10-10-2017
2 10-10-2020
3 10-10-3017
4 11-11-2017
but conversion to a real date does:
select
* , str_to_date(`date`,'%d-%m-%Y')
from (
select '10-10-2017' as 'date' union all
select '11-11-2017' as 'date' union all
select '10-10-1989' as 'date' union all
select '10-10-2020' as 'date' union all
select '10-10-3017' as 'date'
) table1
where str_to_date(`date`,'%d-%m-%Y') between str_to_date('10-10-2017','%d-%m-%Y') and str_to_date('11-11-2017','%d-%m-%Y')
order by str_to_date(`date`,'%d-%m-%Y')
date str_to_date(`date`,'%d-%m-%Y')
1 10-10-2017 10.10.2017 00:00:00
2 11-11-2017 11.11.2017 00:00:00
Demo
In addition: The way "between" is implemented in SQL is that the first value must be lower than the second value (i.e. the sequence of the value IS vital). That is because "between" is really just a syntax shortcut for somevalue >= compare_val_low and somevalue <= compare_val_high if you reverse the comparison values it will return NULL unless somevalue happens to equal one or both of the comparison values. Using strings it will be easy for what appears to be a lower date, to in fact be a "higher value" due to the nature of string ordering, e.g. this might "look" ok:
between '29-08-2017' and '11-11-2017'
but it is not OK at all because '29' is higher than '11' and between will return no rows.

Select from database where date is less than a supplied date

I'm trying to pull rows from a database where the date is within two weeks of the current date, I'm using CodeIgniter and this is my model:
function GetToDoItems($userID)
{
$range = date('Y-m-d', strtotime("+2 weeks"));
$query = $this->db->query("SELECT * FROM FYP_Milestones
INNER JOIN FYP_Modules ON FYP_Milestones.ModuleID = FYP_Modules.ID
WHERE FYP_Milestones.MilestoneDue < $range
ORDER BY FYP_Milestones.MilestoneDue ASC
");
return $query->result();
}
It runs this query:
SELECT * FROM FYP_Milestones INNER JOIN FYP_Modules ON FYP_Milestones.ModuleID = FYP_Modules.ID WHERE FYP_Milestones.MilestoneDue < 2016-04-14 ORDER BY FYP_Milestones.MilestoneDue ASC
I have a row in the database like so:
Considering 2016-04-07 is less than 2016-04-14 by 7 days I'm expecting that row alone to be pulled, but SQL is returning an empty result , why is this the case?
You actually don't need PHP for the range, use SQL:
WHERE FYP_Milestones.MilestoneDue < (CURDATE() + INTERVAL 2 WEEK)
Add single quotes to the date value like:
$query = $this->db->query("SELECT * FROM FYP_Milestones
INNER JOIN FYP_Modules ON FYP_Milestones.ModuleID = FYP_Modules.ID
WHERE FYP_Milestones.MilestoneDue < '".$range."'
ORDER BY FYP_Milestones.MilestoneDue ASC
");

Using Date_Sub to subtract year with Aliases column

I have two column brand and date_time and during select I assign them to aliases. The query below:
SELECT brand,
YEAR(date_time) AS 'year',
SUM( brand = 'KFC' ) AS kfc
SUM( brand = 'PZH' ) AS pzh,
SUM( brand = 'SUB' ) AS sub
FROM scan_report
GROUP BY YEAR(date_time)
Result to this:
Now here's the confuse part. How can I use Date_Sub function to display data only for the last 5 years. I mean user will enter 2014 and will only display/select record from the last 5 year that means from 2010 to 2014.
Using WHERE such as this gave me empty records:
SELECT
YEAR(date_time) AS 'year',
SUM( brand = 'KFC' ) AS kfc
SUM( brand = 'PZH' ) AS pzh,
SUM( brand = 'SUB' ) AS sub
FROM scan_report WHERE DATE_SUB(2014, INTERVAL 5 YEAR)
GROUP BY YEAR(date_time)
or this
FROM scan_report WHERE DATE_SUB(year = 2014, INTERVAL 5 YEAR)
Any idea how I can retrieve record from the last 5 years of user input? I prefer to solve this problem with mysql, if no solution is found than I'll go with php. Thanks in advance.
Do this simple math in PHP:
$year = 2014; # from $_POST or anywhere else
$from = ($year - 4) . '-01-01 00:00:00';
$to = $year . '-12-31 23:59:59';
And then use this 2 variables in query.
$sql = "
...
WHERE date_time BETWEEN '$from' AND '$to'
...
";
demo
UPDATE (calculation in SQL):
If you don't want to calculate in PHP, you can then calculate in MySQL:
$sql = "
...
WHERE
date_time BETWEEN CONCAT({$year}-4, '-01-01 00:00:00') AND CONCAT({$year}, '-12-31 23:59:59')
...
";
UPDATE (don't care about speed or indexes):
$sql = "
...
WHERE
YEAR(date_time) AND {$year}-4 AND {$year}
...
";
Your problem is that the predicate in the WHERE clause is returning NULL for every row, so no rows are being returned.
The DATE_SUB function takes a DATE expression as the first argument, not an integer. That is, you could specify '2014-01-01' as the first argument, rather than 2014. That would return a non-zero date, which would evaluate to TRUE (in a boolean context) so all rows would be returned.
To include rows that have particular values of date_time, you'd need to use a comparison in the predicate (WHERE clause). To return rows with date_time values of '2009-01-01' and later...
SELECT YEAR(t.date_time) AS year
, SUM( t.brand = 'KFC' ) AS kfc
, SUM( t.brand = 'PZH' ) AS pzh
, SUM( t.brand = 'SUB' ) AS sub
FROM scan_report t
WHERE t.date_time >= DATE_SUB('2014-01-01', INTERVAL 5 YEAR)
GROUP BY YEAR(date_time)
Some additional notes: if you need (or want) to escape an identifier (e.g. a column name, because it's a reserved word), enclose the identifier in backtick characters, not single quotes, e.g.
SELECT YEAR(`t`.`date_time`) AS `year`

php query returns missing data

I have a problem with my php query for getting data. Let me explain what I want. I have a database which saves the active users for some hours in a day. For example 01-01-2012 13:00
active = 5 01-01-2012 14:00 active = 10. My php query should make an array which contains 2 columns which are date and active. But date must be like 01-01-2012 withour hours. So I grouped them as date2 but I couldn't find the active(sum) for each days. Here is my query which doesn't give the right active sums.
$query2 = mysql_query("SELECT DATE_FORMAT(date, '%Y-%m-%d') AS date2, SUM(active) FROM hit WHERE game= '".$game."' AND source = '".$source."' AND date > '".$dateFrom."' AND date < '".$dateTo."' GROUP BY date2 ORDER BY date2");
while($tuple= mysql_fetch_array($query2)){
$myArr[] = $tuple;
}
print_r($myArr);
You need to alias SUM(active) and GROUP BY date. If date is a datetime, you can GROUP BY DATE(date). Also, be careful with reserved words and make sure to use tick marks where necessary.
Further, if you are looking for an inclusive date range, you should know that when you send 2012-10-03, it is actually 2012-10-03 00:00:00 and any records between 00:00:00 and 23:59:59 will be ignored.
Lastly, you should stop using mysql_ functions as they are being deprecated.
This query should work:
$query2 = mysql_query("
SELECT DATE_FORMAT(`date`, '%Y-%m-%d') AS date2, SUM(active) AS active
FROM hit
WHERE game= '".$game."' AND source = '".$source."'
AND `date` > DATE_SUB('".$dateFrom."', INTERVAL 1 SECOND)
AND `date` < DATE_ADD('".$dateTo."', INTERVAL 1 DAY)
GROUP BY DATE(`date`)
ORDER BY `date`");
$i = 0;
while($tuple= mysql_fetch_array($query2)){
$myArr[$i][date2] = $tuple[date2];
$myArr[$i][active] = $tuple[active];
$i++;
}
print_r($myArr);
Your array ($myArr) would then look something like:
Array
(
[0] => Array
(
[date2] => 2012-10-03
[active] => 5
)
)

Group By and displaying entries under date

Here's my data:
id date
1 2009-01-01 10:15:23
2 2009-01-01 13:21:29
3 2009-01-02 01:03:13
4 2009-01-03 12:20:19
5 2009-01-03 13:01:06
What I'd like to do is group by each date and then list the id numbers below each date. Should I be getting the distinct date values and then cycling through them to get the entries that fall on the date? is this efficient?
so my output would look like:
2009-01-01
1
2
2009-01-02
3
2009-01-03
4
5
$query = "SELECT DATE(date) as mydate, id FROM your_data_table ORDER BY mydate, id";
$result = $pdo->query($query);
$oldDate = false;
while ( list($date, $id) = $result->fetch(PDO::FETCH_NUM) ) {
if ( $oldDate != $date ) {
echo "$date\n$id\n";
$oldDate = $date;
} else {
echo "$id\n";
}
}
Instead of doing it in several queries, you just fetch all the data at once. If you only need some dates then you just put a WHERE clause before the ORDER BY.
Your stored dates have time information (the type of the column is DATETIME or TIMESTAMP), in order to do a group by, you need to extract only the date part your timespan, you can use the DATE() function.

Categories