How to echo days with no results in while loop? - php

I want to count the number of posts for each day to create a graph. My problem is that since SQL doesn't find results for some days (Count is 0), I'm missing rows I need for the chart (since I do want to show days with no posts).
SELECT DATE(Date) AS Day, COUNT(*) AS COUNT
FROM `Posts`
GROUP By `Day`
ORDER BY Date DESC
while($row = mysql_fetch_array($result)) {
echo $row['Date'] . ": " . $row['Count'];
}
Since the loop doesn't display days with 0 results, if on wednesday there are no posts I get: monday-17-3: 5, tuesday-18-3: 2, thursday-20-3: 3. Instead I want to fill out the blanks so I get something like: wednesday-19-3: 0.
How can I echo the days with no results in the loop?

You can work around this by a table of dates, performing an OUTER JOIN, and then performing the grouping. This will provide you with the dates in between (Disclaimer: I'm assuming your dates are in the format YYYY-MM-DD, otherwise you may need to tweak the JOIN statement slightly.).
SELECT A.Date AS Day, COUNT(Posts.Date) AS COUNT
FROM
(
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) A
LEFT OUTER JOIN `Posts` ON A.Date = `Posts`.`Date`
WHERE A.Date >= DATE_ADD(CURDATE(), INTERVAL -15 DAY)
GROUP BY A.Date
For the date table, I'm using the method from the following post: generate days from date range

Use a loop to go through successive dates, using a function like:
$date = strtotime(date("Y-m-d", strtotime($date)) . " +1 day");
For each cycle, apply your query result. Then you'll have all the dates.

Related

Make zero instead of null if there are no records in for mysql SUM query with group by [duplicate]

This question already has answers here:
MySQL how to fill missing dates in range?
(6 answers)
Closed 3 years ago.
I writes a query to get the result like sum of the amount for each product group by date.
When getting the output some products does not have corresponding amount for the date.that dates are not listing in the output So i need every date to display and if amount is there it need to show the amount otherwise 0.
I tried using IFNULL and COALESCE but getting same output.
My OUTPUT
date amount
2019-05-16 499
2019-05-17 1998
2019-05-18 999
2019-05-19 999
Needed output should look like this
date amount
2019-05-16 499
2019-05-17 1998
2019-05-18 999
2019-05-19 999
2019-05-20 0
query for getting data from mysql
$query = "select date, SUM(amount) as amount from product_details where date between '2019-05-16 00:00:00' and '2019-05-20 23:59:59' and prodid = 1 group by date";
Is there any way to make appear the date which does not have amount?
Try this. First we generate a record set of all dates between curdate() and first jan. Change curdate() to end date and 1 jan to start date.
Then we outer join this with your table and use it to group by date.
With cal as (SELECT a.Days
FROM (
SELECT curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY AS Days
FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c
) a
WHERE a.Days >= '2019-01-01' and a.Days<=curdate())
SELECT cal.Days as date, sum(p.amount) as amount FROM cal LEFT JOIN product_details p on cal.Days=p.date and p.prodid=1 group by cal.Days

0 When no row exist

I have following sql query
SELECT DATE_FORMAT(date,'%d.%m. %y') as date, COUNT(idStat) as number
FROM stat
WHERE IdGame = ? AND date >= ? AND date <= ?
GROUP BY date
It returns date and how much people visited game this day, but how to return 0, when no rows exist this day?
For example day 15.12.1993 does not exist in db, but user pick date between 15.10.1950 and 12.15.2020.
I want to return this non existing date 15.12.1993 but with count 0.
Is this even possible?
Thanks for help,
Filip.
The best way is to have a Calendar table handy with relevant dates. You can then use a left join to get the dates. Something like this:
SELECT DATE_FORMAT(c.date,'%d.%m. %y') as date, COUNT(s.idStat) as number
FROM Calendar c LEFT JOIN
stat s
ON c.date = s.date AND s.IdGame = ?
WHERE c.date >= ? AND c.date <= ?
GROUP BY c.date;
If you have games on every date but the problem is that the particular game is not one the day, you can use this short-cut:
SELECT DATE_FORMAT(date,'%d.%m. %y') as date, SUM(IdGame = ?) as number
FROM stat
WHERE date >= ? AND date <= ?
GROUP BY date;
This doesn't work in all cases, but it can be a useful short-cut.
I used RedFilter Answer to solve my problem, from this link: generate days from date range
My query now looks like this:
select DATE_FORMAT(a.Date,'%d.%m. %Y'), COUNT(stat.IdStat)
from (
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) as a LEFT JOIN stat ON a.Date = stat.date
where a.Date between ? and ? AND (stat.IdGame = ? OR stat.IdGame IS NULL) GROUP BY a.Date
But I need remove future dates form my datapicker, because when i use futue date in this sql, no data will be return... I need set min and max of my datapicker.

MySQL inner join three tables to use in calendar

Following up my question where I used the answer to generate data on my calendar called maintenance calendar showing the aircraft's maintenance schedule. This is the MySQL query for it:
SELECT DISTINCT s.reg AS 'reg',
a.date AS 'date'
FROM (SELECT Curdate()
+ INTERVAL (a.a + (10 * b.a) + (100 * c.a)) day AS Date
FROM (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS c) a
INNER JOIN maintenance_sched s
ON a.date >= s.date_from
AND a.date <= s.date_to
WHERE Month(date) = '".$month."'
AND Dayofmonth(date) = '".$dayArray["mday"]."'
AND Year(date) = '".$year."'
Here is the maintenance_sched database:
And the calendar looks like this (based on the data from maintenance_sched):
Then, I have another calendar called reservation calendar with the same code as the maintenance calendar though with different query. This is the reservation calendar query: SELECT acode FROM reservation WHERE month(etd) = '".$month."' AND dayofmonth(etd) = '".$dayArray["mday"]."' AND year(etd) = '".$year."' ORDER BY etd".
The reservation table is this:
And the reservation calendar looks like this:
EDIT:
What I want to do is: have these two calendar in one calendar with the result of maintenance_sched query outputted as string with strikethrough. But I can't seem to make the two queries work out together as one.
I do think the answer to this question is to simply join the two queries. An example of this might be like below where you just null out any columns that aren't in your second table.
SELECT id, date, field3, description
FROM table1
UNION
SELECT id, date, field3, null
FROM table2
As there is no relationship among both the table we cannot go for joins, it would be better to go for UNION to combine the result.
This query uses group_concat so will generate common results in following form
2013-03-15 | RP-C1728, RP-C1086
2013-03-08 | RP-C1728, RP-C1086, RP-C143
If you dont want record in this format then just remove group_concat, group by clause from the query.
Query
SELECT a.date, group_concat(a.reg)
FROM
(SELECT DISTINCT s.reg AS 'reg',
a.date AS 'date'
FROM (SELECT Curdate()
+ INTERVAL (a.a + (10 * b.a) + (100 * c.a)) day AS Date
FROM (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS c) a
INNER JOIN maintenance_sched s
ON a.date >= s.date_from
AND a.date <= s.date_to
WHERE Month(date) = '".$month."'
AND Dayofmonth(date) = '".$dayArray["mday"]."'
AND Year(date) = '".$year."'
UNION ALL
SELECT acode as 'reg', date as 'date' //Add the date logic here as per your need
FROM reservation
WHERE month(etd) = '".$month."' AND
dayofmonth(etd) = '".$dayArray["mday"]."' AND
year(etd) = '".$year."' ORDER BY etd) a
GROUP BY a.date;
NOTE For the second query add the according date logic

TIMEDIFF GROUP BY involved days

I am searching for a way to get the TIMEDIFF of two timestamps grouped by involved days in MySQL.
SELECT TIMEDIFF('2012-01-02 10:00:00', '2012-01-01 10:00:00');
This is just giving the diff of 24 hours.
I need the diff of both (or maybe more) days. i.e.:
2012-01-01: 14:00:00
2012-01-02: 10:00:00
[...]
Is there a way to group in the TIMEDIFF function?
In order to do what you want, you need to generate a sequence of numbers. Perhaps you have a table. If not, something like the following:
select dstart + interval n.num days
from (select d1*10+d2 as num
from (select 0 as d union all select 1 union all select 2 union all
select 3 union all select 4 union all select 5 union all select 6 union all
select 7 union all select 8 union all select 9
) d1 cross join
(select 0 as d union all select 1 union all select 2 union all
select 3 union all select 4 union all select 5 union all select 6 union all
select 7 union all select 8 union all select 9
) d2
) n join
(select date('2012-01-02') as dend, date('2012-01-01') dstart
on dstart + interval n.num days <= dend
(This is not tested, so it might have syntax errors.)

MySQL query get 0 if no result for day

I am creating a line graph in flot, I have it all working except for the days which do not have a result I need them to come back with a result 0 + date. Is this possible in mysql? Here is my current query:
$chartQuery = "SELECT count(date) as counted_leads, UNIX_TIMESTAMP(date) as time FROM enquiries WHERE visibility != 'deleted' group by date";
Or would I need to do it in my php? Here is my code:
<?php
$last_key = end(array_keys($chartResults));
foreach ($chartResults as $item => $value)
{
$timestamp = round($value['time'] * 1000);
if ($item == $last_key)
{
// last element
echo '['.$timestamp.', '.htmlentities($value['counted_leads']).']';
}
else
{
// not last element
echo '['.$timestamp.', '.htmlentities($value['counted_leads']).'],';
}
}
unset($value);
?>
SELECT
ifnull(count(date),0) as counted_leads,
UNIX_TIMESTAMP(date) as time
FROM enquiries WHERE visibility != 'deleted'
group by date
Use if null for defult value
I think this is what you are looking for:
SELECT time, SUM(counted_leads) AS counted_leads
FROM(
SELECT UNIX_TIMESTAMP(date) AS time, count(1) AS counted_leads
FROM enquiries
WHERE visibility != 'deleted'
GROUP BY time
UNION ALL
SELECT a.Date AS time, 0 AS counted_leads
FROM (
SELECT CURDATE() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY AS Date
FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c
) a
WHERE a.Date BETWEEN (SELECT MIN(date) FROM enquiries) AND (SELECT MAX(date) FROM enquiries)
) a
GROUP BY time;

Categories