Selecting row with max value from a subquery, without using LIMIT - mysql

Let's say I have a table films(film, category).
I want to find the category with the most films. How do I do that without using LIMIT?
I suppose I could do something like this:
SELECT category
FROM
(SELECT category, COUNT(*) AS num
FROM films
GROUP BY category) AS T1
WHERE num =
(SELECT MAX(num)
FROM
(SELECT category, COUNT(*) AS num
FROM films
GROUP BY category) AS T2)
But is there a more elegant way of doing that? Preferably one where I don't have to write the same subquery multiple times?
Thanks!
(And if you're wondering why I can't use LIMIT, it's for homework)

you could do it using a variable to create a row number:
SELECT category
FROM
(
SELECT
category
COUNT(*) as NumOfFiles
,(#rn:= #rn + 1) as RowNumber
FROM
Films f
CROSS JOIN (SELECT #rn:=0) vars
GROUP BY
category
ORDER BY
COUNT(*) DESC
) t
WHERE
t.RowNumber = 1

Related

Is there a way to list distinct field results from multiple columns

I have a few tables where I want to look at distinct values for a number of fields within them.
Eg.
ID | Category | sub_category | item
Is there a way where I can return a unique result set for each field?
Essentially I just want to see all distinct values for a different columns in a table within one result set.
I've tried joins but i need the results to be mutually exclusive of one another.
Each returned field won't necessarily have the same matching number of rows either.
Can you just use union all?
select distinct 'category', category
from t
union all
select distinct 'subcategory', subcategory
from t;
EDIT:
If you want the values in different columns:
select c.category, s.subcategory
from (select category, row_number() over (order by category) as seqnum
from t
group by category
) c full join
(select subcategory, row_number() over (order by subcategory) as seqnum
from t
group by subcategory
) s
on c.seqnum = s.seqnum;
You can extend this for additional columns by adding more subqueries and full joins.
EDIT II:
Older versions of MySQL support neither window functions nor full join. You can do something similar, enumerating each value and then aggregating:
select max(category) as category,
max(subcategory) as subcategory
from ((select (#rnc := #rnc + 1), category, null as subcategory
from (select distinct category from t
) c cross join
(select #rnc := 0) params
) union all
(select (#rns := #rns + 1), null as category, subcategory
from (select distinct subcategory from t
) s cross join
(select #rns := 0) params
)
) sc
group by rn;

how to use min as a condition in sql query

cat use min as condition
the where statement is where it breaks but i cant fix it
select category, count(*) as number_of_cats
from books
where number_of_cats > min(number_of_cats)
group by category
order by category;
Having + sub-query
select category, count(*) as number_of_books
from books
group by category
having count(*) > -- check the one whose count is STRICTLY greater then minimum
( select min (st.t) -- find the minimum of all categories
from
( select count(*) as t --find the count for all categories
from books
group by category
) st -- an alias to avoid parsing errors
)
Another option, but with this solution in case of ex-aequo only first category is removed:
select select category, count(*) as number_of_books
from books
where category not in (select bb.category
from books bb
group by bb.category
order by count(*) asc
limit 1)
group by category
You could use common table expressions here, e.g.:
WITH CategoryCount AS (
SELECT
category,
COUNT(*) AS number_of_books
FROM
books
GROUP BY
category),
MinBooks AS (
SELECT
MIN(number_of_books) AS min_number_of_books
FROM
CategoryCount)
SELECT
cc.*
FROM
CategoryCount cc
CROSS JOIN MinBooks m
WHERE
cc.number_of_books > m.min_number_of_books;

Particular MySql Query

Having the following tables
Post(*id, name, description, cat, publish_date)
Category(*id, name)
It is possible in ONE query to get (max) the first N element of each different category?
Assuming that N=3, i'd need the following result:
Result set:
["1", "Name1","Descr","cat1"]
["2", "Name1","Descr","cat1"]
["3", "Name1","Descr","cat1"]
["10","Name1","Descr","cat2"]
["20","Name1","Descr","cat2"]
["22","Name1","Descr","cat2"]
["25","Name1","Descr","cat3"]
["30","Name1","Descr","cat3"]
["19","Name1","Descr","cat3"]
And so on.
I need this, to get the first N article of EACH category, with one query (so without ask for a specific category but for all category in table)
It is possible? If yes what's the right query?
This query will do what you need. If any category has less than 3 post it will still work.
SELECT P.id,P.name,P.description,C.name
FROM Post P
LEFT JOIN Category C
ON P.type = C.id
WHERE FIND_IN_SET(P.id,
(
SELECT GROUP_CONCAT(ids) FROM
(SELECT SUBSTRING_INDEX(GROUP_CONCAT(id),',',3) as ids
FROM Post
GROUP BY type
) AS foo
GROUP BY ''
)
)
Here is a working SQL Fiddle
UPDATE
In response to your comment and updated question:
SELECT P.id,P.name,P.description,P.publish_date,C.name
FROM Post P
LEFT JOIN Category C
ON P.type = C.id
WHERE FIND_IN_SET(P.id,
(
SELECT GROUP_CONCAT(ids) FROM
(SELECT SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY publish_date DESC),',',3) as ids
FROM Post
GROUP BY type
) AS foo
GROUP BY ''
)
)
You can use UNION to join multiple queries into one. This assumes that you know what type you are selecting for each set.
SELECT * FROM
(
SELECT * FROM T1 WHERE type='Type1' ORDER BY id DESC LIMIT 3
) DUMMY1
UNION ALL
SELECT * FROM
(
SELECT * FROM T1 WHERE type='Type2' ORDER BY id DESC LIMIT 3
) DUMMY2
UNION ALL
SELECT * FROM
(
SELECT * FROM T1 WHERE type='Type3' ORDER BY id DESC LIMIT 3
) DUMMY3
The DUMMY table aliases are needed to allow ordering within each subquery.

show all data only group by specific rows : Select * from table group by column having column = 'value'

I use mysql. My table look like this:
Last I try to use this query
SELECT * FROM movie GROUP BY `group` HAVING cateogry = 'TV'
I want with this query result as: show all but only GROUP BY TV category, where category = 'TV'
I want this Result
But my query give me this result (HAVING in query work as WHERE clouse)
IF I use this QUERY
SELECT * FROM movie GROUP BY `group`
It give me this result
I want -> QUERY -> GROUP BY group (ID no 9 and ID 1,2,3 treat as different group name)
IF group has all same values BUT category='movie' (RETURN ALL ROWS
group by NOT APPLY)
IF group has all same values BUT category='TV' (RETURN 1 ROW group by APPLY)
You seem to want this query:
select m.*
from movie m join
(select `group`, min(id) as minid
from movie
group by `group`
) g
on m.id = g.minid;
SELECT min(ID) as ID, min(Name), `group`, Category
FROM movie
GROUP BY `group`, Category
ORDER BY ID
Have you tried the below? I think you are pretty close. As when you are grouping your 'group' t. You are also grouping the one whose category is movie as well. So you just need to create a separate group Category.
SELECT * FROM movie
WHERE group = 't'
GROUP BY group, Category
ORDER BY ID

Obtain a list with the items found the minimum amount of times in a table

I have a MySQL table where I have a certain id as a foreign key coming from another table. This id is not unique to this table so I can have many records holding the same id.
I need to find out which ids are seen the least amount of times in this table and pull up a list containing them.
For example, if I have 5 records with id=1, 3 records with id=2 and 3 records with id=3, I want to pull up only ids 2 & 3. However, the data in the table changes quite often so I don't know what that minimum value is going to be at any given moment. The task is quite trivial if I use two queries but I'm trying to do it with just one. Here's what I have:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = MIN(SELECT COUNT(*) FROM table GROUP BY id)
If I substitute COUNT(*) = 3, then the results come up but using the query above gives me an error that MIN is not used properly. Any tips?
I would try with:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = (SELECT COUNT(*) FROM table GROUP BY id ORDER BY COUNT(*) LIMIT 1);
This gets the minimum selecting the first row from the set of counts in ascendent order.
You need a double select in the having clause:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = (SELECT MIN(cnt) FROM (SELECT COUNT(*) as cnt FROM table GROUP BY id) t);
The MIN() aggregate function is suposed to take a column, not a query. So, I see two ways to solve this:
To properly write the subquery, or
To use temp variables
First alternative:
select id
from yourTable
group by id
having count(id) = (
select min(c) from (
select count(*) as c from yourTable group by id
) as a
)
Second alternative:
set #minCount = (
select min(c) from (
select count(*) as c from yourTable group by id
) as a
);
select id
from yourTable
group by id
having count(*) = #minCount;
You need to GROUP BY to produce a set of grouped values and additional select to get the MIN value from that group, only then you can match it against having
SELECT * FROM table GROUP BY id
HAVING COUNT(*) =
(SELECT MIN(X.CNT) AS M FROM(SELECT COUNT(*) CNT FROM table GROUP BY id) AS X)