mysql: сгруппировать по идентификатору, получить наивысший приоритет для каждого идентификатора - PullRequest
4 голосов
/ 23 июня 2010

У меня есть следующая таблица mysql, которая называется «фото», со следующими полями и примерами данных:

id   vehicle_id    filename    priority
1    45            a.jpg       4
2    45            b.jpg       1
3    56            f.jpg       4
4    67            cc.jpg      4
5    45            kt.jpg      3
6    67            gg.jpg      1

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

Результат, который я ищу:

array (
  [0] => array( [id] => '2', [vehicle_id] => '45', [filename] => 'b.jpg',  [priority] => '1' ),
  [1] => array( [id] => '3', [vehicle_id] => '56', [filename] => 'f.jpg',  [priority] => '4' ),
  [2] => array( [id] => '6', [vehicle_id] => '67', [filename] => 'gg.jpg', [priority] => '1' )
);

Если это невозможно в одном запросе, какой подход лучше всего подходит?

Спасибо!

Ответы [ 3 ]

5 голосов
/ 23 июня 2010

Обратите внимание, что этот метод был опубликован до того, как стало ясно, что он необходим для обработки приоритетных связей. Я оставляю это здесь для справки (см. Комментарии ниже). Проверьте @ ответ Марка для решения, которое обрабатывает связи как требуется:

SELECT p.id, p.vehicle_id, p.filename, p.priority
FROM   pics p
JOIN   (
           SELECT   vehicle_id, MAX(priority) max_priority
           FROM     pics
           GROUP BY vehicle_id
       ) sub_p ON (sub_p.vehicle_id = p.vehicle_id AND 
                   sub_p.max_priority = p.priority)
GROUP BY p.vehicle_id;

Предполагается, что для одной и той же vehicle_id.

не может быть приоритетных связей.

Контрольный пример:

CREATE TABLE pics (id int, vehicle_id int, filename varchar(10), priority int);

INSERT INTO pics VALUES ('1', '45', 'a.jpg', '4');
INSERT INTO pics VALUES ('2', '45', 'b.jpg', '1');
INSERT INTO pics VALUES ('3', '56', 'f.jpg', '4');
INSERT INTO pics VALUES ('4', '67', 'cc.jpg', '4');
INSERT INTO pics VALUES ('5', '45', 'kt.jpg', '3');
INSERT INTO pics VALUES ('6', '67', 'gg.jpg', '1');

Результат:

+------+------------+----------+----------+
| id   | vehicle_id | filename | priority |
+------+------------+----------+----------+
|    1 |         45 | a.jpg    |        4 |
|    3 |         56 | f.jpg    |        4 |
|    4 |         67 | cc.jpg   |        4 |
+------+------------+----------+----------+
3 rows in set (0.01 sec)
5 голосов
/ 23 июня 2010

Хотя это может быть «принятым» ответом, производительность решения Марка при нормальных обстоятельствах во много раз лучше и одинаково верна для вопроса, поэтому непременно обращайтесь к его решению в производстве !


SELECT a.id, a.vehicle_id, a.filename, a.priority
FROM pics a
LEFT JOIN pics b               -- JOIN for priority
ON b.vehicle_id = a.vehicle_id 
AND b.priority > a.priority
LEFT JOIN pics c               -- JOIN for priority ties
ON c.vehicle_id = a.vehicle_id 
AND c.priority = a.priority 
AND c.id < a.id
WHERE b.id IS NULL AND c.id IS NULL

Предполагая, что id является необнуляемым столбцом.

[править]: плохо, мне нужно второе соединение, я не могу сделать это только с одним.

5 голосов
/ 23 июня 2010

Кажется, это типичный максимальный запрос группы.В большинстве баз данных вы можете легко сделать это, используя ROW_NUMBER:

SELECT id, vehicle_id, filename, priority
FROM (
    SELECT 
        id, vehicle_id, filename, priority,
        ROW_NUMBER() OVER (PARTITION BY vehicle_id
                           ORDER BY priority DESC, id) AS rn
    FROM pics
) AS T1
WHERE rn = 1

Поскольку MySQL еще не поддерживает ROW_NUMBER, вы можете эмулировать его с помощью переменных:

SELECT id, vehicle_id, filename, priority
FROM (
    SELECT
        id, vehicle_id, filename, priority,
        @rn := CASE WHEN @prev_vehicle_id = vehicle_id
                    THEN @rn + 1
                    ELSE 1
               END AS rn,
        @prev_vehicle_id := vehicle_id
    FROM (SELECT @prev_vehicle_id := NULL) vars, pics T1
    ORDER BY vehicle_id, priority DESC, id
) T2
WHERE rn = 1
...