MYSQL return 0 on hourly count - mysql

I am at a loss of how to accomplish this but have seen online ISNULL() and COALESCE() used to return a zero if the query is null. I am unsure though how to use it properly though I am intuitively thinking i need to have in a subquery then have ISNULL or COALESCE around that subquery?
The query goes:
SELECT HOUR( dateAdded ) AS HOUR , COUNT( DISTINCT remoteAddr, xForwardedFor) AS cnt
FROM Track
WHERE accessMask = '1iczo'
AND destination = 'lp_include.php'
AND dateAdded
BETWEEN '2014-05-01'
AND '2014-05-02'
GROUP BY HOUR
ORDER BY HOUR
Some help in the right direction would be greatly appreciated!
UPDATE
I used what #Barmar had suggested but it wasn't returning accurate results. I used what he provided and also another topic with a similar situation, Group by should return 0 when grouping by hours. How to do this? . I actually didn't find this topic till after posting this one, :( unfortunately. Here is the final code that appears to return accurate results, distinct across two columns with empty data being returned as 0.
SELECT a.hour, COALESCE(cnt, 0) AS cnt
FROM (SELECT 0 AS hour
UNION ALL
SELECT 1
UNION ALL
SELECT 2 .....
UNION ALL
SELECT 23) a
LEFT JOIN
(SELECT COUNT(DISTINCT remoteAddr, xForwardedFor) AS cnt, HOUR(dateAdded) AS hour
FROM Track
WHERE accessMask = '1iczo'
AND destination = 'lp_include.php'
AND dateAdded
BETWEEN '2014-05-01 00:00:00' AND '2014-05-01 23:59:59') AS totals
ON a.hour = totals.hour
Fiddle for better reference: http://sqlfiddle.com/#!2/9ab660/7
Thanks again to #Barmar, he really put me in the right direction to get to the solution!

You have to join with a table that contains all the hours. This must be a LEFT JOIN so that the results will include hours that have no matches in Track table.
SELECT allHours.hour, IFNULL(cnt, 0) AS cnt
FROM (SELECT 0 AS hour
UNION
SELECT 1
UNION
SELECT 2
UNION
SELECT 3
...
UNION
SELECT 23) AS allHours
LEFT JOIN
(SELECT HOUR(dateAdded) AS hour, COUNT(DISTINCT remoteAddr, xForwardedFor) AS cnt
FROM Track
WHERE accessMask = '1iczo'
AND destination = 'lp_include.php'
AND dateAdded
BETWEEN '2014-05-01' AND '2014-05-02') AS totals
ON allHours.hour = totals.hour

If you assume that you have some data for every hour, you can move the conditional part into the select:
SELECT HOUR(dateAdded) AS HOUR ,
COUNT(DISTINCT CASE WHEN accessMask = '1iczo' AND destination = 'lp_include.php'
THEN CONCAT(remoteAddr, ',', xForwardedFor)
END) AS cnt
FROM Track
WHERE dateAdded BETWEEN '2014-05-01' AND '2014-05-02'
GROUP BY HOUR
ORDER BY HOUR;

Related

Find number of rows for each hour where datetime columns match certain criteria

RDBMS: MySQL
The time column(s) datatype is of datetime
For every hour of the 24 hour day I need to retrieve the number of rows in which their start_time matches the hour OR the end_time is great than or equal to the hour.
Below is the current query I have which returns the data I need but only based off of one hour. I can loop through and do 24 separate queries for each hour of the day but I would love to have this in one query.
SELECT COUNT(*) as total_online
FROM broadcasts
WHERE DATE(start_time) = '2018-01-01' AND (HOUR(start_time) = '0' OR
HOUR(end_time) >= '0')
Is there a better way of querying the data I need? Perhaps by using group by somehow? Thank you.
Not exactly sure if i am following, but try something like this:
select datepart(hh, getdate()) , count(*)
from broadcasts
where datepart(hh, starttime) <=datepart(hh, endtime)
and cast(starttime as date)=cast(getdate() as date) and cast(endtime as date)=cast(getdate() as date)
group by datepart(hh, getdate())
Join with a subquery that returns all the hour numbers:
SELECT h.hour_num, COUNT(*) AS total_online
FROM (SELECT 0 AS hour_num UNION SELECT 1 UNION SELECT 2 ... UNION SELECT 23) AS h
JOIN broadcasts AS b ON HOUR(b.start_time) = h.hour_num OR HOUR(b.end_time) >= h.hour_num
WHERE DATE(b.start_time) = '2018-01-01'
GROUP BY h.hour_num

How to find which year do values tend to increase in ? in SQL

Basically I have a table like this:
Table Time:
ID.......Date
1......08/26/2016
1......08/26/2016
2......05/29/2016
3......06/22/2016
4......08/26/2015
5......05/23/2015
5......05/23/2015
6......08/26/2014
7......04/26/2014
8......08/26/2013
9......03/26/2013
The query should return like this
Year........CountNum
2016........4
2015........3
To find out which year does its value tend to increase in. I notice that I want to display the years that have more values (number of row in this case) than the previous year.
What I've done so far
SELECT Year, count(*) as CountNum
FROM Time
GROUP BY Year
ORDER BY CountNum DESC;
I don't know how to get the year from date format. I tried year(Date) function, but I got Null data.
Please help!
It should works fine.
select year(date), count(*) as countNum
from time
group by year(date)
order by countNum
Join the grouped data to itself with 1 year offset:
select
a.*
from
(
select year(`Date`) as _year, count(*) as _n
from time group by 1
) a
left join
(
select year(`Date`) as _year, count(*) as _n
from time group by 1
) b
on a._year = b._year-1
where a._n > b._n
order by 1

Totalling query in last row

This query will return a list of engineer names with test results for what they have tested in the last hour, what is faulty, what's is working and the total for each engineer.
I want to be able to add a row at the bottom which will total these amounts but am struggling, any one have any suggestions?
select distinct qcheck.checkby,
ifnull(fully,0) as fully,
ifnull(faulty,0) as faulty,
ifnull(lasthour,0) as lasthour,
ifnull(total,0) as total
from qcheck
left join (
select count(*) AS fully,
checkby,
qcheck.id
from qcheck
where result = 'fully tested & working'
and date(finishdate) = CURDATE()
group by checkby) AS fw
on fw.checkby=qcheck.checkby
left join (
select count(*) AS faulty,
checkby,
qcheck.id
from qcheck
where result = 'faulty'
and date(finishdate) = CURDATE()
group by checkby) AS ff
on ff.checkby=qcheck.checkby
left join (
select count(*) AS Lasthour,
checkby,
qcheck.id from qcheck
where finishdate >= now() - interval 1 hour
group by checkby) AS lh
on lh.checkby=qcheck.checkby
left join (
select count(*) AS total,
checkby,
qcheck.id from qcheck
where date(finishdate) = CURDATE()
group by checkby) AS total
on total.checkby=qcheck.checkby
where date(finishdate) = CURDATE()
and qcheck.checkby not like 'michael'
and qcheck.checkby not like 'chaz'
group by qcheck.checkby
order by total desc
First of all, you don't need the sub queries, you can instead do a count on a condition.
The with rollup modifier can be added to the group by clause to include the grand total. The order by cannot be used in the same query then, but can be applied in an outer query.
Furthermore, with the use of coalesce you can replace the null value for that total row with the label of your choice.
Finally, to still sort the total row at the end, you could add an is null expression in the order by clause, which will evaluate to false or true. The latter is ordered last.
select coalesce(checkby, 'Total') as checkby_or_total,
fully,
faulty,
lasthour,
total
from (
select qcheck.checkby,
count(case result when 'fully tested & working' then 1 end) as fully,
count(case result when 'faulty' then 1 end) as faulty,
count(case when finishdate >= now()-interval 1 hour then 1 end) as lasthour,
count(*) as total
from qcheck
where date(finishdate) = CURDATE()
and qcheck.checkby not like 'michael'
and qcheck.checkby not like 'chaz'
group by qcheck.checkby with rollup
) as main
order by checkby is null,
total desc

Find first buisness day of next month MySQL without function

We have a date_value column and another Boolean column which indicates whether the day is a business day or not.
We are trying to find the first business day of the next month( example, for September, 2015 I want it to return 2015-10-01)
We have tried a couple different methods involving last_day, intervals and subqueries but can't quite get it to work.
We also don't have the ability to create custom functions, which makes this a little more difficult.
I think you want something like this:
select min(date_value) fwd
from tablename
where isWorkDay = 1 and
extract(year from date_value)=extract(year from curdate()) and
extract(month from date_value)=extract(month from curdate()) + 1
For all months (v0.3) (please note that I can test this now, so it might have some error):
select t1.month_number, min(t2.date_value)
from tablename t1 join
tablename t2 on extract(year from t1.date_value) * 12 + t1.month_number = extract(year from t2.date_value) * 12 + t2.month_number - 1
where t2.isWorkDay = 1
group by t1.month_number
I was able to get it using the below
SELECT
d.year
,d.month_number
,first_business_period as next_month_first_period
,d2.previous_business_day
FROM lk_date d
JOIN (
SELECT
a.*
, MAX(CASE WHEN d2.business_period_in_days<>0 THEN d2.date_value ELSE NULL END) AS previous_business_day
FROM(
SELECT
d1.year
,d1.month_number
, MIN(CASE WHEN d1.business_period_in_days <> 0 THEN d1.date_value END) AS first_business_period
FROM lk_date d1
GROUP BY 1,2
) a
JOIN lk_date d2 ON d2.date_Value < a.first_business_period
GROUP BY 1,2,3) d2 on d2.previous_business_day = d.date_value

Select distinct while also grouping by hour

I have have this query but cannot make it work properly when I specify a distinct count. I know the syntax must be off somewhere but I am at a loss where.
The group by query that accurately counts by hour is:
SELECT HOUR(dateAdded) AS Hour,
COUNT(dateAdded) AS `user_count`
FROM Track
WHERE dateAdded BETWEEN '2014-04-01' AND '2014-05-02'
OR dateAdded IS NULL
GROUP BY HOUR(dateAdded)
ORDER BY Hour
The new statement with the distinct count adjustments is as follows:
SELECT HOUR(dateAdded) AS Hour,
COUNT(DISTINCT remoteAddr, xForwardedFor) AS `user_count`
FROM Track
WHERE dateAdded BETWEEN '2014-05-01' AND '2014-05-02'
OR dateAdded IS NULL
AND accessMask = '1iczo'
GROUP BY HOUR(dateAdded)
ORDER BY Hour
I know this might be abstract without reference to actual data, I can update the question if you need it for reference.
UPDATE
The answer that was posted put me in the right direction in terms of thinking about the solution but I don't believe it was returning an accurate result. I came up with this solution instead and in case it is useful for anyone else, posted it. This can probably be done much better but its what I was able to come up with and gives accurate results.
SELECT HOUR( dateAdded ) AS HOUR , COUNT( DISTINCT remoteAddr, xForwardedFor ) AS cnt
FROM Track
WHERE accessMask = '1iczo'
AND destination = 'lp_include.php'
AND dateAdded
BETWEEN '2014-05-01'
AND '2014-05-02'
GROUP BY HOUR
ORDER BY HOUR
I think you should do that with a subquery
Don't think you can't do a count(distinct ...) on two columns.
SELECT hour, count(*) as user_count
from
(SELECT HOUR(dateAdded) AS Hour,
remoteAddr,
xForwardedFor
FROM Track
WHERE dateAdded BETWEEN '2014-05-01' AND '2014-05-02'
OR dateAdded IS NULL
AND accessMask = '1iczo'
GROUP BY HOUR(dateAdded), remoteAddr, xForwardedFor) s
group by hour
order by hour