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
Related
In the following query I want to always display the rows even if the SUM result is 0.
Without the WHERE clause it works fine, but when I want to filter between dates, no result is returned. What detail is failing?
SELECT tc.cars,
COALESCE(SUM(ts.sales),0) AS cars_sales
FROM tbl_cars tc
LEFT JOIN tbl_sales ts ON tc.id_cars = ts.id_cars
WHERE tc.recDate BETWEEN '2017-04-01' AND DATE_ADD( '2017-05-01' , INTERVAL 1 DAY)
GROUP BY tc.cars
ORDER BY tc.cars;
SQLFiddle: http://www.sqlfiddle.com/#!9/425e6d/1/0
Use this instead:
SELECT tc.cars,
COALESCE(SUM(ts.sales),0) AS cars_sales
FROM tbl_cars tc
LEFT JOIN tbl_sales ts ON tc.id_cars = ts.id_cars
and tc.recDate BETWEEN '2017-04-01' AND DATE_ADD( '2017-05-01' , INTERVAL 1 DAY)
GROUP BY tc.cars
ORDER BY tc.cars;
After your join has executed, where clause will filter the entire dataset based on the condition provided in where clause. Since your dataset has no entries for the months of April and May, the empty result-set is expected.
Put the condition on the JOIN instead. Also, I think you mean to COUNT() the fields, since ts.sales is VARCHAR in your schema, and also empty in your sample data.
SELECT
tc.cars, COALESCE(COUNT(ts.sales), 0) AS cars_sales
FROM
tbl_cars tc
LEFT JOIN
tbl_sales ts ON tc.id_cars = ts.id_cars
AND tc.recDate BETWEEN '2010-04-01' AND DATE_ADD('2020-05-01', INTERVAL 1 DAY)
GROUP BY tc.cars
ORDER BY tc.cars;
Fiddle
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.
SELECT *,
DATE(date) AS post_day
FROM notes
WHERE MONTH(date) = '08'
AND userid = '2'
AND YEAR(date) = '2016'
ORDER BY post_day DESC,
timestamp ASC
In this query I'm grouping my posts by day.
What I'm struggling with is calculating the total word count of all notes for each day. There is a word count column which contains the word count for each post. Is it possible to calculate this sum in the same query or does it need to be made separately?
By table columns:
NoteID UserID Date Note WordCount
SELECT date, SUM(wordCount) AS monthWordCount
FROM Notes
WHERE userID = 2
AND MONTH(date) = '08'
AND YEAR(date) = '2016'
GROUP BY userID, date
Check out this demo using the above code.
If you want to return the notes as well you can do a subquery like below:
SELECT noteID, userID, date, note, wordCount,
(SELECT SUM(wordCount)
FROM Notes
WHERE userID = a.userID
AND date = a.date
GROUP BY userID) AS dayTotalWordCount
FROM Notes a
WHERE a.userID = 102
AND MONTH(date) = '08'
AND YEAR(date) = '2016'
Here's a demo using the above code.
First, don't use select * with a group by query. select * just doesn't make sense with aggregation . . . you need to apply aggregation functions.
I assume that you want something like this:
SELECT DATE(date) as post_day, SUM(WordCount)
FROM notes
WHERE MONTH(date)= '08' AND userid = '2' AND YEAR(date)= '2016'
GROUP BY DATE(date)
ORDER BY post_day DESC, timestamp ASC
I have a query which successfully returns a single value where "day" is hardcoded in the query, as below:
SELECT MAX(theCount) FROM
(SELECT FK_Hour, Count(FK_Hour) As theCount FROM
(Select FK_Hour
From slottime
INNER JOIN time ON slottime.FK_Hour = time.Hour
WHERE FK_Hour IN
(SELECT time.Hour FROM time WHERE time.day=0 )
) As C
GROUP By FK_Hour
) AS counts;
I'm trying to remove this hardcoding such that two columns; namely
day:theCount are returned.
I have tried
SELECT MAX(theCount), day FROM
(SELECT FK_Hour, day As day, Count(FK_Hour) As theCount FROM
(Select slottime.FK_Hour, time.day
From slottime
INNER JOIN time ON slottime.FK_Hour = time.Hour
) As C
GROUP By FK_Hour
) AS counts
GROUP By day;
and it executes. However the values it returns are obviously incorrect (no obvious correlation to the data in the tables being queried)
In the first example, if I am reading this right, you are getting the count of records for day = 0 for each fk_hour value, and selecting the max count from that.
To do this for all days, start by writing an aggregation query to get the count of each day and hour pair like this:
SELECT t.day, t.hour, COUNT(*) AS numRecords
FROM time t
GROUP BY t.day, t.hour;
Once you have that, you can get the maximum value by using limit 1:
SELECT t.day, t.hour, COUNT(*) AS numRecords
FROM time t
GROUP BY t.day, t.hour
ORDER BY COUNT(*) DESC
LIMIT 1;
This query will return one row, and tell you at which day and which hour the highest number of records occurred.
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;