SQL-запрос для групповой выборки других данных из этой строки - PullRequest
0 голосов
/ 23 ноября 2018

У меня есть следующая схема:

CREATE TABLE `a` (
  `id` char(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `c_id` char(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `d_id` char(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO a VALUES ('1673b492fe9049a5bda9dcea56e9de6a', '1673b49303d04aadba461c27726f8cb8', '16328bc433604fe0af1329a0c2bc0312');

INSERT INTO a VALUES ('163b75aeafe0479aa426e506c687da91', '1673b49303d04aadba461c27726f8cb8', '15fbace119504b1db81bb6409b77fb26');

INSERT INTO a VALUES ('161ad54eb7f042c584881ed6dec31e68', '16328bc433604fe0af1329a0c2bc0312', '160705a0b0304a02b00ec47c2c84f99b');

SQLFiddle

Мне нужен запрос, который в основном выглядит как select c_id, max(id), d_id from a group by c_id, в который поступают данныеиз строки, которая соответствует MAX(id)

Конечно, это невозможно в режиме SQL, который допускает только полную группу:

Выражение № 3 списка SELECT отсутствует вПредложение GROUP BY и содержит неагрегированный столбец 'a.d_id', который функционально не зависит от столбцов в предложении GROUP BY;это несовместимо с sql_mode = only_full_group_by

Возможно ли это, и как мне это сделать?Желательно без объединения.

1 Ответ

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

В производной таблице вы можете получить максимальные значения id (последние id) для каждого c_id.Затем вы можете присоединить этот набор результатов к основной таблице, чтобы получить только строку, соответствующую последнему id.

Просмотр запроса 1 на скрипте БД

SELECT a.* 
FROM a 
JOIN (SELECT c_id, max(id) AS max_id 
      FROM a 
      GROUP BY c_id) AS dt
  ON dt.c_id = a.c_id AND 
     dt.max_id = a.id

Результат

| id                               | c_id                             | d_id                             |
| -------------------------------- | -------------------------------- | -------------------------------- |
| 161ad54eb7f042c584881ed6dec31e68 | 16328bc433604fe0af1329a0c2bc0312 | 160705a0b0304a02b00ec47c2c84f99b |
| 1673b492fe9049a5bda9dcea56e9de6a | 1673b49303d04aadba461c27726f8cb8 | 16328bc433604fe0af1329a0c2bc0312 |

Поскольку вы явно ищете решение, не использующее JOIN, мы можем использовать Пользовательскийпеременные .Мы определим номер строки в пределах группы c_id с наибольшим значением id, имеющим номер строки 1. В конце концов, мы будем рассматривать только те строки, в которых значение номера строки равно 1. Проверьте дальнейшее объяснение здесь: https://stackoverflow.com/a/53465139/2469308

Примечание , что CROSS JOIN не присоединяется к фактической таблице;вместо этого это трюк для инициализации пользовательских переменных в пределах одного запроса.

Один примечательный момент здесь заключается в том, что ваш столбец c_id определен с CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci.Таким образом, при инициализации переменных нам нужно явно обеспечить одинаковый набор символов и сопоставление.В противном случае мы получим ошибку "Недопустимое смешение параметров сортировки" .Это происходит потому, что строковые переменные по умолчанию инициализируются с сортировкой utf8mb4_general_ci.Мы будем использовать функцию CAST(..), чтобы обеспечить инициализацию с помощью utf8mb4_unicode_ci.

SELECT
dt2.id, dt2.c_id, dt2.d_id 
FROM 
(
  SELECT
    dt1.id, dt1.c_id, dt1.d_id, 
    @rn := CASE WHEN @cid = dt1.c_id THEN @rn + 1
                WHEN @cid := dt1.c_id THEN 1
           END AS row_num 
  FROM   
  (
     SELECT
       id, c_id, d_id 
     FROM a 
     ORDER BY c_id, id DESC
  ) dt1
  CROSS JOIN 
  (
     SELECT 
       @rn := 0, 
       @cid := CAST('' AS CHAR(32) CHARACTER SET utf8mb4) COLLATE utf8mb4_unicode_ci 
  ) AS user_vars 
) dt2 
WHERE dt2.row_num = 1

Просмотр запроса 2 на скрипте БД

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...