Порядок с групповыми рядами вместе

Возникла проблема со сложным заказом.

Вот структура и данные:

CREATE TABLE `mail_test` (
  `id` int(10) UNSIGNED NOT NULL,
  `account_id` int(10) UNSIGNED NOT NULL,
  `score` float UNSIGNED NOT NULL,
  `from` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


INSERT INTO `mail_test` (`id`, `account_id`, `score`, `from`) VALUES
(1, 1, 0, '[email protected]'),
(2, 2, 0, '[email protected]'),
(3, 3, 3, '[email protected]'),
(4, 5, 4, '[email protected]'),
(5, 3, 1, '[email protected]'),
(6, 9, 0.5, '[email protected]'),
(7, 9, 3, '[email protected]'),
(8, 8, 2, '[email protected]');

Желаемый результат:

(4, 5, 4, '[email protected]'),
(7, 9, 3, '[email protected]'),
(3, 3, 3, '[email protected]'),
(5, 3, 1, '[email protected]'),
(8, 8, 2, '[email protected]');
(6, 9, 0.5, '[email protected]'),
(1, 1, 0, '[email protected]'),
(2, 2, 0, '[email protected]'),

Логика порядка: сначала идет строка с наибольшим количеством очков (родительская строка), затем строки (дочерние строки) с одинаковыми account_id и from с родительской строкой. Если нет дочерних строк - снова следующая строка с большим счетом. Итак, сортируйте по счету DESC. Но строки сгруппированы по одинаковым account_id и from.

майскл версии 5.7

Пожалуйста, добавьте желаемый результат.

P.Salmon 11.05.2023 16:35

Что сложного в порядке сортировки? Что вы пытались (написать сами), чтобы получить желаемый результат?

Luuk 11.05.2023 16:51

@Mikael Микаэль, я добавил запрос в ответ. Попробуй это.

Developer 11.05.2023 17:20
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
3
58
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это можно сделать с помощью row_number() и max() :

with cte as (
  select *,
           max(score) over (partition by account_id, `from`) as max_score,
           row_number() over (partition by account_id, `from` order by score, id) as rn
  from mail_test
)
select id, account_id, score, `from`
from cte
order by max_score desc, rn desc

Это рабочее решение для mysql 5.7:

select mt.*
from `mail_test` mt
inner join (
  select account_id, `from`, max(score) as max_score
  from `mail_test`
  group by account_id, `from`
) as s on s.account_id = mt.account_id and s.`from` = mt.`from`
order by max_score desc, id

Результат :

id  account_id  score   from
4   5           4       [email protected]
3   3           3       [email protected]
5   3           1       [email protected]
7   9           3       [email protected]
8   8           2       [email protected]
6   9           0.5     [email protected]
1   1           0       [email protected]
2   2           0       [email protected]

Демо здесь

Ответ принят как подходящий
SELECT *
FROM mail_test
ORDER BY MAX(score) OVER (PARTITION BY account_id, `from`) DESC,
         account_id, `from`,
         ROW_NUMBER() OVER (PARTITION BY account_id, `from` ORDER BY score DESC) 
идентификатор account_id счет от 4 5 4 м@м.com 3 3 3 [email protected] 5 3 1 [email protected] 7 9 3 [email protected] 8 8 2 [email protected] 6 9 0,5 [email protected] 1 1 0 [email protected] 2 2 0 [email protected]

рабочий пример

@Mikael Правильно - группы могут иметь одинаковый максимальный балл. Зафиксированный. Группы (3,5) и (7) в моем выводе не соответствуют порядку в желаемом вами выводе, но вы не указали необходимые критерии для сортировки таких групп. Например, это можно исправить с помощью .. ORDER BY .. account_id DESC, ...

Akina 11.05.2023 16:57

возможно ли это на mysql 5.7? извините, я обновил сообщение, версия mysql 5.7

Mikael 11.05.2023 16:59

Эмулируйте оконные функции с помощью JOIN + GROUP BY или используйте пользовательские переменные.. но я рекомендую вам обновить версию MySQL.

Akina 11.05.2023 17:00

И как вы думаете, если я перейду с 5.7 на 8 - высоки шансы что-то сломать?

Mikael 11.05.2023 17:02

@Mikael 50/50 - либо успех, либо нет. Бэкап (проверен на его восстанавливаемость) поможет.

Akina 11.05.2023 17:04

Эта версия работает без разделов:

SELECT m.`id`, m.`account_id`, m.`score`, m.`from`
FROM mail_test m
LEFT JOIN mail_test parent_m
  ON m.account_id = parent_m.account_id
  AND m.from = parent_m.from
  AND m.score < parent_m.score
GROUP BY m.id, m.account_id, m.score, m.from
ORDER BY IFNULL(MAX(parent_m.score), m.`score`) DESC

Практически идеально ! Но [email protected] с оценкой 3 должен быть выше [email protected] с оценкой 1.

Mikael 11.05.2023 17:19

Я немного подправил, теперь должен показывать правильный порядок (хотя и с двусмысленностью относительного порядка id 3 и id 7)

Rob Eyre 11.05.2023 19:12

Другие вопросы по теме