Возвращение строк с максимальными значениями (несколько) в mySQL - PullRequest
0 голосов
/ 28 октября 2018

У меня следующий запрос:

select
    a.dormid, a.student_capacity, count(*) as num
from
    (select
       d.dormid, 
       d.dorm_name, 
       d.student_capacity, 
       h.amenid
     from
       (Dorm d left join Has_amenity h 
       on d.dormid=h.dormid)
    ) a
group by a.dormid, a.student_capacity

, который дает мне следующий результат:

+--------+------------------+-----+
| dormid | student_capacity | num |
+--------+------------------+-----+
|    109 |              128 |   8 |
|    104 |              256 |   3 |
|    160 |              400 |  12 |
|    100 |               85 |   5 |
|    117 |               40 |   1 |
|    110 |              116 |   5 |
|    140 |              355 |   6 |
+--------+------------------+-----+

Я хочу получить только строки dorm_id и student_capacity с максимальными значениями 'num'(но учтите связи, поэтому я не могу ограничить количество строк до 1).Так что в этом случае верните [160, 400, 12].

Как мне подойти к этому?Я пытался поставить where num = max(num) после кода, но это не сработало.Я думаю, что использование функции rank и ограничение rank = 1 могут помочь, но я не уверен, где мне следует это реализовать.

Ответы [ 3 ]

0 голосов
/ 28 октября 2018

Прежде всего, я думаю, что вы без необходимости используете запрос подвыбора ( Производная таблица ), чтобы получить текущий результат. Поскольку вы не выполняете дополнительную фильтрацию результата подзапроса; вы можете покончить с подзапросом и все же получить тот же результат более эффективно:

SELECT 
 d.dormid, 
 d.student_capacity, 
 COUNT(d.dormid) AS num 
FROM Dorm AS d 
LEFT JOIN Has_amenity AS h 
 ON h.dormid = d.dormid 
GROUP BY d.dormid, d.student_capacity 

Теперь вам в основном нужна функциональность Dense_Rank() (ранг 1 - общежитие с максимальными удобствами). Оконные функции доступны только в MySQL версии 8.0.2 и далее .

В версиях MySQL <8.0.2 </strong> мы можем использовать определяемые пользователем переменные , чтобы вычислить то же самое. Основная суть этого подхода заключается в получении набора результатов в требуемом порядке в производной таблице. В этом случае нас интересует общежитие с наивысшим рейтингом; таким образом, мы получаем набор результатов в порядке убывания num.

Теперь мы используем две переменные сеанса для хранения предыдущих значений строк, чтобы определить текущие значения строк, в предложении Select. В основном мы храним значения предыдущих строк rank и num; и if значение num текущей строки отличается от предыдущего, мы увеличиваем rank.

В конце концов, снова используя этот результат в качестве производной таблицы, нам просто нужно рассмотреть только те строки, где rank = 1 (с использованием предложения Where.)

Попробуйте следующий запрос (будет работать для всех версий MySQL):

SELECT dt2.*
FROM 
(
  SELECT 
    dt.dormid, 
    dt.student_capacity, 
    @drank := IF(@n <> dt.num, @drank + 1, @drank) AS rank, 
    @n := dt.num AS num 
  FROM   
  (
    SELECT 
     d.dormid, 
     d.student_capacity, 
     COUNT(d.dormid) AS num 
    FROM Dorm AS d 
    LEFT JOIN Has_amenity AS h 
     ON h.dormid = d.dormid 
    GROUP BY d.dormid, d.student_capacity 
    ORDER BY num DESC 
  ) AS dt 
  CROSS JOIN (SELECT @drank := 0, 
                     @n := 0) AS user_init_vars 
) AS dt2 
WHERE dt2.rank = 1
0 голосов
/ 28 октября 2018

Агрегатные функции, такие как MAX, MIN, AVE и т. Д., Принадлежат разделу select запроса, а не where. Кроме того, вы не можете вкладывать агрегатные функции, поэтому Max (Count *)) не будет работать. Тем не менее, вы МОЖЕТЕ вкладывать выборки и таким образом вкладывать агрегатные функции таким образом. Следующий пример взят из OMG Ponies в аналогичном посте здесь: Могу ли я сделать max (count (*)) в SQL

SELECT MAX(y.num) FROM 
    (SELECT COUNT(*) AS num FROM TABLE x) y

Для такого простого и начального запроса, как я, я бы порекомендовал этот подход, потому что он проще, но ответ Мадхура и ваши инстинкты использовать Ранг тоже отлично работают.

0 голосов
/ 28 октября 2018

Если вы используете MySQL версии 8, вы можете попробовать что-то вроде этого, используя WITH предложение:

WITH
counts AS (select dorm_id,count(*) as num from Dorm)
select dormid, dorm_capacity,count(*) 
from Dorm 
having count(*)=(select max(num) from counts)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...