Можно ли выполнить эту задачу более эффективно? MySQL

#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;
 

db<>скрипка

Комментарии:

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;
 

Я думаю, что это было бы полезно в вашем случае, я проверил все условия в своем локальном, он будет работать должным образом

Снимок Экрана Для Лучшего Понимания:

Снимок Экрана Для Лучшего Понимания