MySQL: normalize column from big subquery - mysql

I have a very big subquery:
(SELECT Id, Count [...] FROM Something) Counts
I want to create a score for each Id that is the count divided by the max count.
I tried:
SELECT Id, Count/(SELECT MAX(Count)) AS Score
FROM (SELECT Id, Count [...] FROM Something) Counts
But this only returns the first row!
If I do a GROUP BY Id, all scores are equal to 1 (because the maximum is taken for each Id, and not for all Ids).
Do you know what I can do please? I know that in some contexts we can embed a subquery in a WITH clause, but this is not valid in MySQL.

I believe this is what you need:
Select Id, (Count/(SELECT MAX(Count) FROM Something)) As [Score] FROM Something
Explanation:
I believe you want to take max of all counts in the table. In order to do so you need to perform a subquery on the entire set of the table, versus limiting it to a specific id, or grouping it. When you performed your group by operating on ID, assuming each Id is unique, it is effectively returning Id, Count/Count. As you know any non-zero number divided by itself is 1.

Related

Different output when I include more columns to the select statement in MySQL

Why do I not get the same results when running the two queries? If I run the second one I get the course with the smallest amount of credits and when I run the first one I get the courses ordered by courseid
select min(credits), title, courseid
from course
group by title, courseid
select min(credits)
from course
An aggregation query is any query that has a group by or an aggregation function in the select.
An aggregation query returns one row per group, where a "group" is defined as the unique combination of values of the keys in the group by clause. If there is no group by clause, then all rows are taken to be a single group and one row is returned.
So, your first query returns one row for each combination of title and courseid in the course table. That row contains the minimum value of credits for that combination. If the course table has only one row per courseid, then the results are very similar to the contents of the table.
The second query returns one row overall, with the minimum number of credits of all rows.
If you want to get one row from with the minimum number of credits, then you don't want an aggregation query. Instead, you can use:
select c.*
from course c
order by c.credits
limit 1;
When you use a group by, you are using a sort of "filter", in the first query you group by title, then all the same titles are grouped by courseid, in the second you only select the minimum value of credits without filtering.
Take a look at a group by doc maybe with some graphical examples like this:
https://www.geeksforgeeks.org/sql-group-by/

Count how many rows have a specified value when the value changes with each row

When I was querying a table by a specific id I would also count how many rows in that table shared the same name:
SELECT *, COUNT(name) FROM table WHERE id = 24601
Now I'm no longer querying a table by a specific id, instead getting all of the table's output. Is there a way I could still get that count for each row?
SELECT *, COUNT(this specific row's name) FROM table
If you want to get the count of rows per name, then use GROUP BY:
SELECT name, COUNT(*) AS count
FROM table
GROUP BY name
You'll get one row per distinct value of name, with a second column that has the integer count.
If you also need the other columns for each row, you should write that as a separate query. Don't combine aggregated results with non-aggregated results in the same query.

MySQL MAX Function mixes rows

I have the query SELECT id, MAX(value) FROM table1 and it returns the correct value, but it takes the first id of the table instead of the one corresponding to the value returned (id is primary key).
I've already seen solutions, but they all needed a WHERE clause which i can't use in my case.
I believe what you're trying to do is return the id of the row with the max value. Is that right?
I'm curious why you can't use a WHERE clause?
But ok, using that constraint this can be solved. I'm going to assume that your table is unique on id (if not, you should really talk to whoever built it and ask why ?)
SELECT id, value
FROM table1
ORDER BY value DESC
LIMIT 1
This will sort your table, by value descending (greatest -> least), and then only show the first row (ie, the row with the largest "value").
If your table is not unique on id, you can still group by ID and get the same
SELECT id, max(value) as max_value
FROM table1
GROUP BY id
ORDER BY max_value DESC
LIMIT 1
First, to answer why your query is behaving in the way you observe: I suspect you are running without sql_mode = only_full_group_by as your query would likely generate an error otherwise. As you've noticed, this can lead to somewhat odd results.
If ONLY_FULL_GROUP_BY is disabled, a MySQL extension to the standard SQL use of GROUP BY permits the select list, HAVING condition, or ORDER BY list to refer to nonaggregated columns even if the columns are not functionally dependent on GROUP BY columns. This causes MySQL to accept the preceding query. In this case, the server is free to choose any value from each group, so unless they are the same, the values chosen are nondeterministic, which is probably not what you want.
In this case, since you have no GROUP BY clause, the entire table is effectively the group.
To get one id associated with the largest value in the table, you can select all the rows, order by the value (descending), and then just limit to the first result, no need for the aggregation operator (or a WHERE caluse):
SELECT id, value FROM table1 ORDER BY value DESC LIMIT 1
Note that if there are multiple ids with the (same) max value, this only returns one of them. In the comments, #RaymondNijland points out that this may give different results (for id, the value will always be the maximum) each time you run it, and you can make it more deterministic by ordering by id as well:
SELECT id, value FROM table1 ORDER BY value DESC, id ASC LIMIT 1
Likewise, if there are for some reason multiple values for the same ID, it will still return that ID if one of its rows happens to be the max value -- thankfully this doesn't apply in this case, as you mentioned that id is the primary key.
I think you forgot a group by clause :
SELECT id, MAX(value) FROM table1 GROUP BY id
EDIT : To answer your need you could do
SELECT id, MAX(value)
FROM table1
GROUP BY id
HAVING MAX(value) = (SELECT MAX(value) FROM table1)
This could give you multiple results if you have multiple ids with the max value. In this case you could add "LIMIT 1" to get only one result but that would be quite strange and random.

How to return multiple rows based on maximum value in one of its column in SQL

Suppose I have a table in which there are two fields, name and number ( I am just presenting my problem premise here) and suppose I am to return the row(s) with the maximum of such numbers. If I use the command
SELECT name, MAX(number) FROM tablename;
However, if I have two or more such rows with the maximum numbers, how I am to modify the above query so as to get all the rows?
EDIT: I want it to return all the rows where such a maximum may be found, not just one of the rows, and it should be correctly associated with the right name.
You use a where clause:
select t.*
from tablename t
where t.number = (select max(number) from tablename);
Your query, by the way, only returns the maximum number. It returns an arbitrary value for name that can be from any row.
If you want only one value, you should use:
select t.*
from tablename
order by number desc
limit 1;
You need to use a group by clause in order to have the max number associated with the appropriate name. Hope this works for you.
select
name, max(number)
from
yourtable
group by
name

MySQL get totals from grouped value

I have a table that's setup like this:
**user_items**
user_item_id
user_id
item_id
User's can have the same item_id associated. If I want to see as a whole, how many items there are assigned to users, this is simply a count.
However, I'd like to the total count factoring in distinct item_id's. So grouping by the item_id, but as a total.
Any idea how I can do this?
Thank you
Select count(*) from ...
is what you are looking for
EDIT: I'm sorry.. This is indeed wrong.
There must be an easier solution, but this will do what you want:
select count() from (select count() from YOURTABLE group by YOURCOL) as WHATEVER;
This counts the rows in the resulting table of the inner query.