Vitess v8 PlanetScale Ошибка ограничения базы данных MySQL

Использование Vitess v8 (БД PlanetScale) Таблица:

CREATE TABLE `Channel` (
    `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
    `guildId` INTEGER UNSIGNED NOT NULL,
    `name` VARCHAR(64) NOT NULL,
    `description` TEXT NULL,
    `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
    `position` INTEGER NOT NULL,
    `parentId` INTEGER NULL,
    `ratelimit` INTEGER NOT NULL DEFAULT 0,
    `type` ENUM('textChannel', 'categoryChannel') NOT NULL,

    INDEX `Channel_guildId_idx`(`guildId`),
    UNIQUE INDEX `Channel_guildId_name_key`(`guildId`, `name`),
    UNIQUE INDEX `Channel_guildId_position_key`(`guildId`, `position`),
    PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Данные испытаний:

INSERT INTO Channel (id, guildId, name, position, type) VALUES (1, 1, 'ch1', 1, 'textChannel');
INSERT INTO Channel (id, guildId, name, position, type) VALUES (2, 1, 'ch2', 2, 'textChannel');
INSERT INTO Channel (id, guildId, name, position, type) VALUES (3, 1, 'ch3', 3, 'textChannel');

Первый шаг: (это нормально, если вы не понимаете, почему этот шаг важен)

UPDATE `Channel` SET `position` = 0.5 WHERE `id` = 3;

Отредактированный запрос, предоставленный Ergest:

UPDATE `Channel` AS `ch`
INNER JOIN ( 
  SELECT `id` as `id2`,
  ( SELECT COUNT(*)
    FROM (SELECT * FROM `Channel`) AS `b`
    WHERE `b`.`position` <= `a`.`position`
  ) AS `p`
  FROM `Channel` AS `a` WHERE `guildId` = 1
) AS `td` ON `ch`.`id` = `td`.`id2`
SET `ch`.`position` = `td`.`p`;

Ошибка:

error: code = AlreadyExists desc = Duplicate entry '1-2' for key 'Channel.Channel_guildId_position_key' (errno 1062)

он говорит о неправильном использовании UPDATE и LIMIT, но я даже не использую LIMIT.

Average Capitalist 18.03.2022 21:44
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
1
43
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы используете ORDER BY.

Документы MySQL:

Multiple-table syntax: For the multiple-table syntax, UPDATE updates rows in each table named in table_references that satisfy the conditions. Each matching row is updated once, even if it matches the conditions multiple times. For multiple-table syntax, ORDER BY and LIMIT cannot be used.

Я не вижу смысла использовать ORDER BY position ASC внутри подзапроса, если вы не используете LIMIT

Попробуйте использовать INNER JOIN:

UPDATE `Channel` AS `ch`,
INNER JOIN ( 
            SELECT`id`,
                      ( SELECT COUNT(*)
                        FROM `Channel` AS `b`
                        WHERE `b`.`position` <= `a`.`position`
                      ) AS `p`
           FROM `Channel` AS `a` WHERE `guildId` = 1
           ) AS `td` on   `ch`.`id` = `td`.`id`; 
SET `ch`.`position` = `td`.`p` ;

Когда я удаляю ORDER BY, он дает ту же ошибку... И я даже не использую ORDER BY в UPDATE, это запрос SELECT (теперь я удалил ORDER BY, чтобы предотвратить такие же ответы, как этот)

Average Capitalist 18.03.2022 22:23

@AverageCapitalist попробуйте INNER JOIN и дайте мне знать

Ergest Basha 18.03.2022 22:32

Ух ты! Это почти работает! Я понятия не имею, почему это дало мне ошибку... Но там написано "Дублировать запись "1-2"", потому что у меня есть ограничение для уникальной позиции

Average Capitalist 18.03.2022 22:51

Когда я вручную выполняю запрос SELECT, он отображает все просто отлично, а ключ «p» не дублируется. Не уверен, почему MySQL считает, что нарушает ограничение уникального индекса.

Average Capitalist 18.03.2022 22:51

@AverageCapitalist без данных и описания таблицы не могу сказать

Ergest Basha 18.03.2022 22:56

Я думаю, что знаю, почему это происходит... Поскольку MySQL обновляет одну строку за раз, возможно, строка с, например, 0,5 была обновлена ​​​​до 1, но строка с позицией 1 еще не обновлена, поэтому она сломала ограничение?

Average Capitalist 18.03.2022 23:05
db-fiddle.com/f/fZY8dLTbtRFF3Nwe4rPT2L/0 Вот фрагмент скрипта БД! Это повышает ошибку ограничения
Average Capitalist 19.03.2022 00:53

@AverageCapitalist, если вы проверите рабочий пример, вы увидите, что пытаетесь обновить 1 2 значения, которые существуют, и именно так UNIQUE INDEX Channel_guildId_position_key(guildId, position) предполагается работать

Ergest Basha 19.03.2022 09:45

Я прочитал ошибку и теперь понимаю почему, но она должна превращать каждую позицию в 1, 2, 3 соответственно. Это отлично работает в реализации Postgres, но я использую MySQL... Как мне решить эту проблему? Это не должно нарушать ограничение, если весь запрос UPDATE выполнен

Average Capitalist 19.03.2022 21:16

Другие вопросы по теме