#mysql
#mysql
Вопрос:
Я создаю приложение с миллионами строк, поэтому я стараюсь избегать объединения, когда это возможно. У меня есть таблица, подобная этой:
ID category value_1 value_2
1 1 2.2432 5.4321
2 2 6.5423 5.1203
3 1 8.8324 7.4938
4 2 0.4823 9.8244
5 2 7.2456 3.1278
6 1 1.9348 4.4421
Я пытаюсь получить данные value_1
из строки с наименьшим ID
и value_2
из строки с наибольшим идентификатором, сгруппированные по category
, вот так:
category value_1 value_2
1 2.2432 4.4421
2 6.5423 3.1278
Возможно ли это эффективным способом, избегая таких конструкций, как операции со строками и ОБЪЕДИНЕНИЕ?
Спасибо!
Комментарии:
1. Пожалуйста, объясните, почему
6.5423
в ожидаемых результатах отображается значение категории 2. Похоже, это не соответствует вашей логике.2. почему «избегание конструкций, таких как операции со строками и ОБЪЕДИНЕНИЕ»? это не имеет смысла
3. @TimBiegeleisen Из категории 2 наименьший идентификатор равен 2, который имеет значение
6.5423
.4. @ysth Полная таблица содержит больше столбцов и десятки миллионов строк. Сначала я использовал несколько объединений, но это удвоило время загрузки.
Ответ №1:
Попробуйте это:
SELECT
category,
(
SELECT t2.value1
FROM table1 t2
WHERE t2.id = MIN(t1.id)
) as value1,
(
SELECT t3.value2
FROM table1 t3
WHERE t3.id = MAX(t1.id)
) as value2
FROM
table1 t1
GROUP BY
category
;
Создайте и заполните таблицу:
CREATE TABLE `table1` (
`id` INT NOT NULL,
`category` INT NULL,
`value1` DOUBLE NULL,
`value2` DOUBLE NULL,
PRIMARY KEY (`id`)
);
INSERT INTO table1 VALUES
(1, 1, 2.2432, 5.4321),
(2, 2, 6.5423, 5.1203),
(3, 1, 8.8324, 7.4938),
(4, 2, 0.4823, 9.8244),
(5, 2, 7.2456, 3.1278),
(6, 1, 1.9348, 4.4421);
Вывод:
1 2.2432 4.4421
2 6.5423 3.1278
Ответ №2:
Один из подходов, который позволяет избежать объединений, заключается в использовании ROW_NUMBER
:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY category ORDER BY ID) rn_min,
ROW_NUMBER() OVER (PARTITION BY category ORDER BY ID DESC) rn_max
FROM yourTable
)
SELECT
category,
MAX(CASE WHEN rn_min = 1 THEN value_1 END) AS value_1,
MAX(CASE WHEN rn_max = 1 THEN value_2 END) AS value_2
FROM cte
GROUP BY
category;
ДЕМОНСТРАЦИЯ
Редактировать:
Приведенный выше запрос должен использовать следующий индекс:
CREATE INDEX idx ON yourTable (category, ID);
Это должно существенно ускорить операции с номерами строк.
Комментарии:
1. Это действительно дает met правильный ответ, но также выдает ошибку: Обратите внимание на . библиотеки классы Отображение Результаты.php#4241 — Неопределенный индекс: инструкция
2. @JMRC Тогда, возможно, у вашего PHP-скрипта какая-то проблема, или, возможно, вы не используете MySQL 8 . То, что я привел выше, я считаю лучшим ответом без использования объединений.
3. Возможно, это действительно был phpMyAdmin. Я попробую еще раз.
4. К сожалению, это было слишком медленно. Это заняло несколько минут, но 1, потому что это сработало в примере.
5. @JMRC Пожалуйста, попробуйте добавить соответствующий индекс, см. мой обновленный ответ.