#mysql
Вопрос:
В настоящее время у меня есть задача: для представленной таблицы изменить порядок учащихся, заменив четную и нечетную последовательность (пример ниже). Есть только одно условие, если количество студентов нечетное, то это последнее число не должно быть изменено. В настоящее время я написал подобный код, однако для меня он кажется довольно неуклюжим. Насколько по-другому и эффективнее должен быть написан этот код?
CREATE TABLE student (id int, name varchar(128));
INSERT INTO student (id,name) VALUES
(1,'Aurimas'),
(2,'Darius'),
(3,'Eligijus'),
(4,'Giedrius'),
(5,'Justinas');
SELECT CASE
WHEN mod((SELECT id FROM student ORDER BY id DESC LIMIT 1),2) = 0 THEN
CASE
WHEN mod(id, 2) = 0 THEN id-1
ELSE id=id 1
END
ELSE
CASE
WHEN mod(id, 2) = 0 AND id <> (SELECT id FROM student ORDER BY id DESC LIMIT 1) THEN id-1
WHEN mod(id, 2) = 1 AND id <> (SELECT id FROM student ORDER BY id DESC LIMIT 1) THEN id 1
ELSE id
END
END AS new_id, name
FROM student
ORDER BY new_id ASC;
У меня есть это:
id name
1 Aurimas
2 Darius
3 Eligijus
4 Giedrius
5 Justinas
И это должно выглядеть так:
id name
1 Darius
2 Aurimas
3 Giedrius
4 Eligijus
5 Justinas
Ответ №1:
Вы можете сгруппировать свои id
s по значению (id 1) DIV 2
. Затем все, что вам нужно сделать, это поменять минимальный идентификатор на максимальный идентификатор в каждой паре строк и убедиться, что вы правильно обрабатываете случай, когда имеется нечетное количество строк.
Что-то вроде этого:
set @maxId = (select max(id) from student);
select
if (
@maxId = id and mod(id, 2) != 0,
id,
if (
mod((id 1), 2) = 0,
id 1,
id-1
)
) as id,
name
from student
order by id;
Комментарии:
1. Обратите внимание, что на данный момент эти типы пользовательских переменных по существу устарели
2.@Strawberry Что именно является устаревшим? Я смог найти только это примечание к выпуску: Установка пользовательских переменных в операторах, отличных от
SET
устаревших… источник.3.Примечание:
@maxId = id
это сравнение, а не задание.
Ответ №2:
Я не уверен, как вы определяете «эффективный», но как насчет…
select ROW_NUMBER() OVER (
ORDER BY ceiling(id/2), id desc
) new_id,name from student
Эта ROW_NUMBER
функция поддерживается в MySQL с версии 8.0.
РЕДАКТИРОВАТЬ: Я полагаю, что-то подобное удовлетворит придирчивых…
WITH cte (id,n) AS (SELECT id, ROW_NUMBER() OVER (ORDER BY id) n FROM student)
SELECT x.name
, ROW_NUMBER() OVER (ORDER BY CEILING(cte.n/2), x.id desc) new_id
FROM student x
JOIN cte
ON cte.id = x.id;
Ответ №3:
Я бы рекомендовал использовать приведенный ниже запрос, потому что
здесь у него много преимуществ, я рассчитываю только один максимальный идентификатор выбора, но в вашем случае для каждого случая будет выполняться один выбор, это сократит это время, и только один максимальный идентификатор будет использоваться для нечетного случая
ваша четная и нечетная операция одинакова, но в нечетной вы пропускаете последнюю запись, поэтому я добавил это условие
SET @MAXID = (SELECT MAX(ID) FROM STUDENT);
SELECT
CASE
WHEN MOD(@MAXID,2) != 0 AND ID=@MAXID THEN ID
ELSE CASE WHEN MOD(ID, 2) = 0 THEN ID-1 ELSE ID 1 END
END AS NEW_ID, NAME
FROM STACK_USER.STUDENT
ORDER BY NEW_ID ASC;
Я думаю, что это было бы полезно в вашем случае, я проверил все условия в своем локальном, он будет работать должным образом
Снимок Экрана Для Лучшего Понимания: