Using AVG with HAVING - mysql

I looked at a similar question and read the documentation on the average function, but when I tried:
CREATE TABLE tab(
id INT,
score INT
);
INSERT INTO tab VALUES
(1, 22),
(2, 45),
(3, 82),
(4, 87);
SELECT score,AVG(score)
FROM tab
GROUP BY score
HAVING score>AVG(score)
which puts AVG after score, I get
There are no results to be displayed.
How can I get this to work?
Here's the fiddle.

The problem here is that you're aggregating per "score". Doing such operation will bring you the average among one value for each record, hence being AVG(score) = score always.
You need to use the corresponding window function for that purpose (Demo):
WITH cte AS (
SELECT score, AVG(score) OVER() AS average_score
FROM tab
)
SELECT *
FROM cte
WHERE score > average_score
or if you don't mind not selecting the average in your final output (Demo):
SELECT score
FROM tab
WHERE score > (SELECT AVG(score) FROM tab)

Related

How do I find the title of a videogame with the maximum amount of developers working on it ? (SQL query)

Let's say that we have 3 tables which are
videogames, developers, workson.
Under the videogames table, we have attributes such as
videogameid (PK)
title
year
genre
Then for developers we have
developerid (PK)
name
gender
Then for the workson table
videogameid(PK & FK )
developerid (PK & FK )
My attempt at the code:
SELECT MAX(videogameid)
FROM
(SELECT videogameid
FROM workson
GROUP BY videogameid
HAVING COUNT(DISTINCT developerid)>5
)videogames_with_most_developers;
However, I have failed to retrieve the answer with the title ( mainly because I did not select the title) but that's because I can't seem to make the connection.
EDIT: So we have some sample data
where for table videogames we have
INSERT INTO videogames (videogameid, title,year,genre)
VALUES (111,World of Warcraft ,2004, MMORPG);
INSERT INTO videogames (videogameid, title,year,genre)
VALUES (112,Starcraft 2 ,2008, RTS);
For the table developers
we have
INSERT INTO developers( developerid, gender, name)
VALUES ( 98734, M, Johnson);
INSERT INTO developers( developerid, gender, name)
VALUES ( 98735, F, Regina);
INSERT INTO developers( developerid, gender, name)
VALUES (98736, M , Lamar);
For the table workson
INSERT INTO (videogameid, developerid)
VALUES (111, 98734);
INSERT INTO (videogameid, developerid)
VALUES (111,98735);
INSERT INTO (videogameid, developerid)
Values(112,98736);
The expected output should be the title 'World of Warcraft' because it has the maximum number of directors working on it which is 2 whereas title such as 'Starcraft' does not have the maximum number of developers working on it as seen in this sample data
Which columns/aggregate function(MAX,COUNT,AVG etc.) you select in the select query will be shown as a table.
In your query:
SELECT MAX(videogameid) FROM ....
only the id of the video game with the largest value will be displayed. You just select the videogameid with the greatest value.In the second part of the query select videogameid that work more than 5 developers.Again there is no title selected to connect to the outer sql query.
Modified version of your query:
SELECT videogameid,title
FROM videogames WHERE videogameid IN
(SELECT videogameid
FROM workson
GROUP BY videogameid
HAVING COUNT(DISTINCT developerid)>5
);
This query shows videogameid and title with more than 5 developers
Another query:
SELECT COUNT(developerid) AS dev_count,videogameid FROM workson GROUP BY videogameid
ORDER BY dev_count DESC LIMIT 1;
this shows videogameid and number of developers that work on selected video game with the maximum amount of developers working on it.There is no title.
If we want to see the title :
SELECT videogameid,title FROM videogames WHERE videogameid IN
(SELECT videogameid FROM (SELECT COUNT(developerid) AS count,videogameid FROM workson GROUP BY videogameid
ORDER BY COUNT(developerid) DESC LIMIT 1) AS T);
This query shows title and videogameid with the maximum amount of developers working on it.

mysql avg value with specified number of rows

i have a simple table with
value (int), created (timestamp)
i would like to do a query that return an arbitrary number of rows with avg (value) and avg(created). The grouping function is the order by of created, means that if i ask for 2 rows, i should obtain a set based on the first rows ordered by created.
i have the following table:
create table log(value int,created timestamp);
insert into log values
(1,'2016-01-01 00:00:00'),
(2,'2016-01-01 01:00:00'),
(3,'2016-01-01 02:00:00'),
(4,'2016-01-01 03:00:00'),
(5,'2016-01-01 04:00:00'),
(6,'2016-01-01 05:00:00'),
(7,'2016-01-01 06:00:00'),
(8,'2016-01-01 07:00:00'),
(9,'2016-01-01 08:00:00');
http://sqlfiddle.com/#!9/b9a94
i want to retrive 3 rows that should be
2-2016-01-01 01:00:00
5-2016-01-01 04:00:00
8-2016-01-01 07:00:00
it's possible to do it in a single query without using java or php processing?
For example when you group by 3, ordered by creation date. You can change 3 to the size you want to group by.
SELECT avg(sub.value), avg(sub.created)
from (
SELECT #row_number:=#row_number+1 AS row_number,value, created
FROM log, (SELECT #row_number:=0) AS t
ORDER BY created
) sub
group by floor((sub.row_number-1)/3)
UPDATE
if you always want it to be divided in 3 groups based on the number of rows you can do the following:
SELECT avg(sub.value), avg(sub.created)
from (
SELECT #row_number:=#row_number+1 AS row_number, floor((#row_number-1)/c.num) groupid,value, created
FROM log,
(SELECT #row_number:=0) AS t,
(SELECT ceil(COUNT(*)/3) num FROM log) c
ORDER BY log.created
) sub
GROUP BY sub.groupid

Selecting unique column for each row

I have the following table:
'A', '2014-07-28'
'A', '2014-07-27'
'A', '2014-07-20'
'B', '2014-07-21'
'B', '2014-07-20'
'A', '2014-07-22'
'A', '2014-07-22'
'B', '2014-07-22'
'B', '2014-07-24'
'B', '2014-07-27'
I need to get a report of user's login history. The report should show the number of users who logged in unique days.
So for example on 27th, A and B both logged in. Thus the report should show 2.
On 22nd, A logged in twice while B logged in once so the report should show 2.
If I select DISTINCT by user_id, then the same user on different days won't be counted.
If I select DISTINCT by date, then same days with different users won't be counted.
I want the report to count the number of unique IDs on each date. Then sum up for all the days.
What's the best way to do this?
You are going to have to use a Group By Clause to get the count per day
Select user_id, `date`, count(*) As count
From loginTable
Group By user_id, `date`
Then use this another group by in a derived table to sum per user.
Select d.user_id, Sum(*) As TotalCount
From (
Select user_id, `date`, count(*) As count
From loginTable
Group By user_id, `date`) d
Group By d.user_id

How to get counts of different values on the same line?

I need a report with the count of the different values a column has, grouped by date, one output line per date.
The table columns are date, location ID (var) and rating (var). Rating can have only one of four values, ‘A’, ‘B’, ‘C’ or null/blank. I can get one line per date per value with this select, but how can I get the counts for all four values on the same line, for each date?
SELECT date, rating, count(rating) AS ratings
FROM table
GROUP BY date, rating
Use SUM with a boolean as follows:
SELECT
date,
SUM(rating = 'A') AS count_A,
SUM(rating = 'B') AS count_B,
SUM(rating = 'C') AS count_C,
SUM(rating = '' OR rating IS NULL) AS count_blank
FROM yourtable
GROUP BY date

can i use column alias in many positions in the query?

if i managed to make the folowing view in mysql
select id,name,score,total,CALCIT(total - score) as x,(CALCIT(total - score) / total) as per from tblx;
the process CALCIT(total - score) is being caculated two times
how to do some thing like this:
select id,name,score,total,CALCIT(total - score) as `x`,`x`/total as per from tblx;
where CALCIT is a function
MySQL will permit you to use a column alias inside the ORDER BY, GROUP BY clauses, but you won't be able to reuse the alias in the SELECT list. If you really needed to do this, having many instances of the calculated value, you can do a self JOIN which produces the calculation.
SELECT
id,
name,
score,
total,
x,
x / total AS per
FROM tblx JOIN (
/* Subquery JOIN which performs the calculation */
SELECT CALCIT(total - score) AS x FROM tblx xcalc
) ON tblx.id = xcalc.id
This method may be more performant than redoing the calculation in one SELECT, but as with anything, benchmark to find out.
Try something like this:
select *, x/total from (
select id,name,score,total,CALCIT(total - score) as x from tblx;
) as tblx
better you can use inner query --
select id,
name,
score,
total,
X,
X/total as per
from (
select id,
name,
score,
total,
CALCIT(total - score) as X from tblx
)