MySQL - Grouping with subquery - mysql

I am having trouble with a subquery and some grouping. The subquery is selecting from the whole table instead of just the individual groups...my code
SELECT SEC_TO_TIME(TIME_TO_SEC(call_start) - TIME_TO_SEC(call_start)%(30*60)) AS intervals,
COUNT(*) AS OFFERED,
SUM(agent_duration) AS AGENT_SUM,
SUM(TIME_TO_SEC(TIMEDIFF(dequeue_time, enqueue_time))) AS ANS_TIME_SUM,
COUNT(DISTINCT agent_username) AS UNIQUE_AGENTS,
(SELECT COUNT(*) FROM call_detail
WHERE TIME_TO_SEC(TIMEDIFF(dequeue_time, enqueue_time)) < 40) AS SLA,
SUM(queue_duration) AS TOTAL_QUEUE_TIME
FROM call_detail
WHERE DATE(call_start) = CURDATE()
GROUP BY intervals
My goal is to have that subquery just return the number of records where that TIMEDIFF result is less than 40 within that particular interval
Thanks.

I don't think you need a subquery for this. Just do conditional aggregation:
SELECT SEC_TO_TIME(TIME_TO_SEC(call_start) - TIME_TO_SEC(call_start)%(30*60)) AS intervals,
COUNT(*) AS OFFERED,
SUM(agent_duration) AS AGENT_SUM,
SUM(TIME_TO_SEC(TIMEDIFF(dequeue_time, enqueue_time))) AS ANS_TIME_SUM,
COUNT(DISTINCT agent_username) AS UNIQUE_AGENTS,
sum(case when TIME_TO_SEC(TIMEDIFF(dequeue_time, enqueue_time)) < 40 then 1 else 0 end) as SLA,
SUM(queue_duration) AS TOTAL_QUEUE_TIME
FROM call_detail
WHERE DATE(call_start) = CURDATE()
GROUP BY intervals;
You would use the subquery to get a total over all record, not the ones affected by the where clause or the group by.

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

SQL Combining Multiple SELECT Statements

I am trying to build an SQLite query that will collect statistics from a single table.
The table holds a log, of sorts, with several entries per day. I need to get a separate row for each day within the search parameters and then compile the totals of rows within those dates with certain boolean values.
Here is the query I have so far:
SELECT DATE(DateTime) AS SearchDate,
(SELECT COUNT() AS Total
FROM CallRecords
WHERE DATE(DateTime)
BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY DATE(DateTime)
ORDER BY Total DESC) AS Total,
(SELECT COUNT() AS Total
FROM CallRecords
WHERE NoMarket = 1
AND DATE(DateTime)
BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY DATE(DateTime)
ORDER BY Total DESC) AS NoMarkets,
(SELECT COUNT() AS Total
FROM CallRecords
WHERE Complaint = 1
AND DATE(DateTime)
BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY DATE(DateTime)
ORDER BY Total DESC) AS Complaints,
(SELECT COUNT() AS Total
FROM CallRecords
WHERE Voicemail = 1
AND DATE(DateTime)
BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY DATE(DateTime)
ORDER BY Total DESC) AS Voicemails
FROM CallRecords
WHERE DATE(DateTime) BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY SearchDate
And the output:
8/28/2017 175 27 11
8/29/2017 175 27 11
8/30/2017 175 27 11
8/31/2017 175 27 11
9/1/2017 175 27 11
As you can see, it is properly getting each individual date, but the totals for the columns is incorrect.
Obviously, I am missing something in my query, but I am not sure where. Is there a better way to perform this query?
EDIT: I have looked into several of the other questions with near-identical titles here, but I have not found anything similar to what I'm looking for. Most seem much more complicated than what I'm trying to accomplish.
It looks like you have a mess of columns in your CallRecords table with names like Complaint and Voicemail, each of which classifies a call.
It looks like those columns have the value 1 when relevant.
So this query should probably help you.
SELECT DATE(DateTime) AS SearchDate,
COUNT(*) AS Total,
SUM(NoMarket = 1) AS NoMarkets,
SUM(Complaint = 1) AS Complaints,
SUM(Voicemail = 1) AS Voicemails
FROM CallRecords
WHERE DateTime >= '2017-08-27'
AND DateTime < '2017-09-02' + INTERVAL 1 DAY
GROUP BY DATE(DateTime)
Why does this work? Because in MySQL a Boolean expression like Voicemail = 1 has the value 1 when it's true and 0 when it's false. You can sum those values up quite nicely.
Why is it faster than what you have? Because DATE(DateTime) BETWEEN this AND that can't exploit an index on DateTime.
Why is it correct for the end of your date range? Because DateTime < '2017-09-02' + INTERVAL 1 DAY pulls in all the records up until, but not including, midnight, on the day after your date range.
If you're using Sqlite, you need AND DateTime < date('2017-09-02', '+1 day'). The + INTERVAL 1 DAY stuff is slightly different there.
you can doing like this , although i wrote in SQL server
SELECT DATE(DateTime) AS SearchDate,
COUNT() AS TOTAL,
SUM(CASE WHEN NoMarket = 1 THEN 1 ELSE 0 END) AS NoMarkets,
SUM(CASE WHEN Complaint = 1 THEN 1 ELSE 0 END) AS Complaints,
SUM(CASE WHEN Voicemail = 1 THEN 1 ELSE 0 END) AS Voicemails
FROM CallRecords
WHERE DATE(DateTime) BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY SearchDate
SELECT DATE(DateTime) AS SearchDate, Total, NoMarkets, Complaints, Voicemails FROM
(SELECT COUNT() AS Total FROM CallRecords) CR
JOIN
(SELECT COUNT() AS NoMarkets FROM CallRecords WHERE NoMarket = 1) NM
ON CR.DateTime = NM.DateTime
JOIN
(SELECT COUNT() AS Complaints FROM CallRecords WHERE Complaint = 1) C
ON NM.DateTime = C.DateTime
JOIN
(SELECT COUNT() AS Voicemails FROM CallRecords WHERE Voicemail = 1) VM
ON C.DateTime = VM.DateTime
JOIN CallRecords CLR ON VM.DateTime=CLR.DateTime WHERE DATE(CLR.DateTime) >= '2017-08-27' AND DATE(CLR.DateTime) <= '2017-09-02'GROUP BY SearchDate;
This may Output correctly.

How to query rows by month and group by column using mysql?

I have a database that has two columns - result and time
I'm trying to get a count of how many rows exist of each result in a particular month. There are only two options for result success and failure
I've managed to get a count of how many rows there are in each month, but I can't get the individual count of how many success and how many failure there were in each month.
Here is what I have:
SELECT result, MONTH(time) MONTH, COUNT(*) COUNT
FROM mytable
WHERE YEAR(time)=2017
GROUP BY MONTH(time);
I'm looking for a result that provides me with something like there were 12 successes and 8 failures in a particular month.
Any help would be appreciated.
Use conditional aggregation
SELECT result, MONTH(time) MONTH,
sum(result = 'success') as success_count,
sum(result = 'failure') as failure_count
FROM mytable
WHERE YEAR(time) = 2017
GROUP BY result, MONTH(time);
I would use the following query:
SELECT,
DATE_FORMAT(time, '%m %Y') AS month_year,
SUM(CASE WHEN result = 'success' THEN 1 ELSE 0 END) AS success_count,
SUM(CASE WHEN result = 'failure' THEN 1 ELSE 0 END) AS failure_count
FROM mytable
WHERE YEAR(time) = 2017
GROUP BY
DATE_FORMAT(time, '%m %Y')
Note that you should be aggregating by time period alone, and not by the result, which instead is part of the sum in the CASE expression.

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

mysql how to combine two select statement

I have a database with records of date-time and a measurement value.
I've been writing two separate queries, one to return the total count of all daily records between certain times of day for the previous month, and the same query but a count of only when the measurement value is below threshold. I then manually divide the theshold count by total count for each day, and I am able to get a % uptime or SLA.
So I have two questions:
1) Can I combine these two queries into one query. I found the Answer to #1, see below
2) Can I go ahead and do the math in the queries, so what I get returned is just a listing of each day, the count above, the count below, and the % above or below threshold...
Sample data and query are listed below.
TableA
hostname, date_time, value
Sample Query to return days from previous month, excluding weekend days.
SELECT
count(*),
DATE(date_time),
SUM(
CASE WHEN rssi_val < 100
THEN 1
ELSE 0
END
)
FROM TableA
WHERE hostname = 'hostA'
AND DATE(date_time) BETWEEN '2013-07-01' AND '2013-07-31'
AND TIME(date_time) BETWEEN '06:00:00' AND '18:00:00'
AND DAYOFWEEK(date_time) NOT IN (1, 7)
GROUP BY DATE(date_time);
So now I just want to know how to add a 4th column that gives the percent uptime/downtime.
Have you tried this ?
select count(*),
DATE(date_time),
SUM(CASE WHEN rssi_val<100 THEN 1 ELSE 0 END),
SUM(CASE WHEN rssi_val<100 THEN 1 ELSE 0 END)/count(*) as percentage
from TableA
where hostname='hostA'
and DATE(date_time) between '2013-07-01' and '2013-07-31'
and TIME(date_time) between '06:00:00' and '18:00:00'
and DAYOFWEEK(date_time) NOT IN (1,7)
group by DATE(date_time);