Найти разницу между максимальным и вторым максимальным значениями, сгруппированными по столбцам в MySql (8.0.13), без использования предложений order by и limit - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть таблица с идентификаторами столбцов, ad_id, amount_time, которая показывает ID пользователей, рекламу, которую они видели, и сколько раз они их видели.Вот пример данных:

table name: ads

ID | ad_id | amount_time
 1      2        600            
 1      3        300
 3      1        400
 1      3        100
 1      1        700

Мы хотим, чтобы результат показал разницу между max и 2nd max of amount_time, сгруппированными по ID и ad_id

Таким образом, результат равен

ID |ad_id | diff_amount_time
 1    3      200

Я могу получить max и second_max для всей таблицы, выполнив:

select
(SELECT MAX(amount_time) FROM ads) maxtime,
(SELECT MAX(amount_time) FROM ads
WHERE amount_time NOT IN (SELECT MAX(amount_time) FROM ads )) as 
second_max_time

Однако у меня возникают проблемы с включением предложения group by для получения моего результата.Я знаю, что есть способ включить order by и limit 2, чтобы получить максимум и второй максимум, но это вычислительно дорого, и я хочу знать, есть ли другое решение, не заказывая столбец amount_time.

1 Ответ

0 голосов
/ 16 ноября 2018

В MySQL 8.0.2+, самым простым и, возможно, наиболее эффективным способом было бы использование оконных функций .

Мы будем использовать Row_Number() функция, которая будет определять значения номеров строк в комбинации ID и ad_id.Номер строки будет основан на нисходящем порядке значения amount_time.Таким образом, самое высокое значение amount_time будет иметь номер строки 1, а второе самое высокое будет иметь номер строки 2.

Теперь мы будем использовать этот набор результатов как Производная таблица и агрегировать (GROUP BY) по ID и ad_id.Мы можем использовать условные выражения CASE .. WHEN, чтобы определить разницу между самым высоким и вторым самым высоким значением в каждой группе.

SELECT
  dt.ID, 
  dt.ad_id, 
  (MAX(CASE WHEN dt.row_no = 1 THEN dt.amount_time END) - 
  MAX(CASE WHEN dt.row_no = 2 THEN dt.amount_time END)) AS diff_amount_time
FROM 
(
 SELECT 
   ID, 
   ad_id, 
   amount_time, 
   ROW_NUMBER() OVER (PARTITION BY CONCAT(ID, '-', ad_id)
                      ORDER BY amount_desc) AS row_no
 FROM ads 
) AS dt 
GROUP BY dt.ID, dt.ad_id 
-- to remove cases where there is no second highest
-- when there is no second highest amount, then the difference will be null
-- because 5 - null = null
HAVING diff_amount_time IS NOT NULL
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...