Mysql Order By count? - mysql

Actually I'm working with the following table fsa_areas:
Note that each area has a responsible
Now, what I need to do, is to order the same table as following:
Note that now the results are ordered by the the responsible with more areas and at the end the responsible with less areas.
Is there a way to order them in that way?

You can use a COUNT subquery in the ORDER BY clause:
select a.*
from fsa_areas a
order by (select count(*) from fsa_areas a1 where a1.Responsible = a.Responsible) desc
Another way is to get the count in a derived table and join the base table to it
select a.*
from (
select Responsible, count(*) as cnt
from fsa_areas
group by Responsible
) r
join fsa_areas a using(Responsible)
order by r.cnt desc
In MySQL 8 you can use COUNT() as window function:
select *, count(*) over (partition by Responsible) as cnt
from fsa_areas
order by cnt desc

Related

How to use a dynamic limit in sql query

I have a query SELECT * FROM grades WHERE userid = 4123;
I want to limit this query
I have a query SELECT * FROM grades WHERE userid = 4123 LIMIT(2);
This works great but if I want this limit to be dynamic from another query.
SELECT COUNT(id) FROM count_table WHERE course = 131;
doing this gives me a syntax error
SELECT * FROM grades WHERE userid = 4123 LIMIT (SELECT COUNT(id) FROM count_table WHERE course = 131);
if this is not possible at all, then is there an alternative way to achieve this?
please help.!
You can do it in MySQL 8.x using the ROW_NUMBER() function.
Assuming you order the rows by some column (I guessed the column ID... change it as needed), you can do:
select
g.*
from (
select
*,
row_number() over(order by id) as rn -- change ordering as needed
from grades
) g
join (
SELECT COUNT(id) as cnt FROM count_table WHERE course = 131
) c on g.rn <= c.cnt

Trying to figure out how to find the max count

Which team has the most number of members on their roster?
Okay so below is the code that I have input currently. It returns all the teams as well as how many people are on each team. I am not sure how to code it to only display the team with the most members as when I try to use a max function and a count function I get an error.
SELECT Team_Name, COUNT(Member.Student_ID_Num)
FROM Teams
JOIN Member ON Teams.Team_Number = Member.Team_Number
GROUP BY Team_Name
you can try below - using limit and order by desc
Select Team_Name, count(Member.Student_ID_Num) as cnt
from Teams join Member on Teams.Team_Number = Member.Team_Number
group by Team_Name
order by cnt desc
limit 1
If you are using MySQL 8+, then the ROW_NUMBER function comes in handy here:
SELECT Team_Name, cnt
FROM
(
SELECT t.Team_Name, COUNT(*) AS cnt,
ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) rn
FROM Teams t
INNER JOIN Member m
ON t.Team_Number = m.Team_Number
GROUP BY t.Team_Name
) t
WHERE rn = 1;
If you instead want all ties for the highest count, should two or more teams be tied, then replace ROW_NUMBER with RANK.
If you have to do this the old fashioned way, without LIMIT or ROW_NUMBER, then get ready for a really ugly query:
SELECT
t.Team_Name,
COUNT(*) AS cnt
FROM Teams t
INNER JOIN Member m
ON t.Team_Number = m.Team_Number
GROUP BY t.Team_Name
HAVING COUNT(*) = (SELECT MAX(cnt) FROM (SELECT COUNT(*) AS cnt
FROM Teams t
INNER JOIN Member m
ON t.Team_Number = m.Team_Number
GROUP BY t.Team_Name) t );
In order to get the team with the highest member count, we need no join (unless we also want to show the member count). One thing to keep in mind that there may be multiple teams sharing the same maximum member count.
The old fashioned way in standard SQL, before there was any limit clause (FETCH FIRST ROWS in standard SQL) was this:
Count members per team number.
Get the maximum count.
Get the team number(s) with this maximum count.
Get the team(s) for these team numbers.
The query:
select *
from teams
where team_number in
(
select team_number
from member
group by team_number
having count(*) =
(
select max(cnt) as max_cnt
from
(
select count(*) as cnt
from member
group by team_number
) counted
)
);
As of MySQL 8 we would rather use a wnindow function, however:
select *
from teams
where (team_number, 1) in
(
select team_number, rank() over (order by count(*) desc)
from member
group by team_number
);

mysql/postgres window function limit result without subquery

Is it possible to limit the result of a window function, with partitioning, without a subquery? This code is in postgres/mysql. I'm looking for solution in mysql and postgres.
For example: let's say the join is irrelevant to the point of the question.
select acct.name, we.channel, count(*) as cnt,
max(count(*)) over (partition by name order by count(*) desc) as max_cnt
from web_events we join accounts acct
on we.account_id=acct.id
group by acct.name, we.channel
order by name, max_cnt desc;
The result of this query gives:
I only want to show the first line of each of the window's partition.
For example: lines with cnt: [3M,19],[Abbott Labortories,20]
I tried the following that doesn't work (added limit 1 to the window function):
select acct.name, we.channel, count(*) as cnt,
max(count(*)) over (partition by name order by count(*) desc limit 1) as max_cnt
from web_events we join accounts acct
on we.account_id=acct.id
group by acct.name, we.channel
order by name, max_cnt desc;
I only want to show the first line of each of the window's partition. For example: lines with cnt: [3M,19],[Abbott Labortories,20]
You don't actually need a window function here, since the first row's max_cnt will always equal cnt. Instead use DISTINCT ON in combination with the GROUP BY.
From the postgresql documentation
SELECT DISTINCT ON ( expression [, ...] ) keeps only the first row of each set of rows where the given expressions evaluate to equal. The DISTINCT ON expressions are interpreted using the same rules as for ORDER BY (see above). Note that the “first row” of each set is unpredictable unless ORDER BY is used to ensure that the desired row appears first
SELECT DISTINCT ON(acct.name)
acct.name
, we.channel
, COUNT(*) cnt
FROM web_events we
JOIN accounts acct
ON we.account_id=acct.id
GROUP BY 1, 2
ORDER BY name, cnt DESC;
Here's a quick demo in sqlfiddle. http://sqlfiddle.com/#!17/57694/8
1 way I always messed up when I first started using DISTINCT ON is to ensure that the order of expressions in the ORDER BY clause starts with the expressions in the DISTINCT ON. In the above example the ORDER BY starts with acct.name
If there is a tie for first position, the first row that meets the criteria will be returned. This is non-deterministic. It is possible to specify additional expressions in the ORDER BY to affect which rows are returned in this setting.
example:
ORDER BY name, cnt DESC, channel = 'direct'
will return the row containing facebook, if for a given account, both facebook and direct yield the same cnt.
However, note that with this approach, it is not possible to return all the rows that are tied for first position, i.e. both rows containing facebook & direct (without using a subquery).
DISTINCT ON may be combined in the same statement with GROUP BYs (above example) and WINDOW FUNCTIONS (example below). The DISTINCT ON clause is logically evaluated just before the LIMIT.
For instance, the following query (however pointless) shows off the combination of DISTINCT ON with WINDOW FUNCTION. It will return a distinct row per max_cnt
SELECT DISTINCT ON(mxcnt)
acct.name
, we.channel
, COUNT(*) cnt
, MAX(COUNT(*)) OVER (PARTITION BY acct.name) mxcnt
FROM web_events we
JOIN accounts acct
ON we.account_id=acct.id
GROUP BY 1, 2
ORDER BY mxcnt, cnt DESC;
Use a subquery. If you want exactly one row (even if there are ties), then use row_number():
select name, channel, cnt
from (select acct.name, we.channel, count(*) as cnt,
row_number() over (partition by acct.name order by count(*) desc) as seqnum
from web_events we join
accounts acct
on we.account_id = acct.id
group by acct.name, we.channel
) wea
order by name;
You can use rank() if you want multiple rows for an account, in the event of ties.

MySQL CROSS JOIN FROM syntax

I have the following query working
SELECT newTable.Score, COUNT(1) AS Total, COUNT(1) / t.count * 100 AS `Frequency`
FROM mytable newTable
CROSS JOIN (SELECT COUNT(1) AS count FROM mytable) t
GROUP BY newTable.Score
ORDER BY Frequency DESC
However, two things I don't understand from the MySQL docs:
1) I don't understand why there isn't a comma, or a join type, specified in the from clause.
Reading the MySQL docs, this seems necessary.
2) What does the 't' represent in the CROSS JOIN clause?
Any advice appreciated.
The t is the same as the newTable - it is an alias name for the table and the temporary table that the subquery builds.
It is easier to read when the optional as keyword is used
SELECT newTable.Score, COUNT(1) AS Total, COUNT(1) / t.count * 100 AS `Frequency`
FROM mytable as newTable
CROSS JOIN (SELECT COUNT(1) AS count FROM mytable) as t
GROUP BY newTable.Score
ORDER BY Frequency DESC
An alias name replaces the original name of the table with a new one to be used in your query. And you need to give subqueries a name to refer to them in your query too.

how to group by with order by on somewhat complex mysql query

(SELECT dtable.*, new_apps.top as t1 FROM app_detailsvvv as dtable INNER JOIN new_apps ON
new_apps.trackId=dtable.trackId WHERE (SELECT COUNT(*) AS c FROM compositions as dtablev
WHERE parent='169469' AND trackId=dtable.trackId AND new_apps.top > 0)>0) UNION
(SELECT *, 301 FROM app_detailsvvv as dtable WHERE (SELECT COUNT(*) AS c FROM compositions
as dtablev WHERE parent='169469' AND trackId=dtable.trackId)>0) ORDER BY t1 ASC, trackName
ASC LIMIT 0,12
this query brings me duplicates, how can I group by it by trackId ?
Place trackid as part of your SELECT statement ...
SELECT new_apps.trackId,
..etc...
..
..
GROUP BY 1
Make sure the rest of your SELECT items (including the sub-SQL query) have been aggregated - such as MAX, FIRST, SUM or something that groups them into a single result.