MySQL如何在不破坏唯一约束或使用占位符行的情况下更新多行
在MySQL中, 我有一个名为 Channel
的表(由 Prisma ORM 自动生成)
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;
如您所见,有一个 UNIQUE INDEX 约束 Channel_guild_position_key
我怎样才能做一些不破坏这个的事情唯一约束,例如:(我可以使用 SELECT * FROM Channel WHERE guildId = $guildId 获取具有相同 guild_id 的所有行)
更新通道current
的位置字段值到 x
(假设 x 大于 current.position
) 更新 current.position
和位置 x
之间的所有通道,并将其位置字段减少 1
将 current.position
更新为位置 x
基本上,我想将通道移动到某个位置,并且新位置和旧位置之间的所有内容都需要向前推进。但我被我设置的约束所阻止,该约束使 (position, guildId)
成为唯一标识符,因此需要一个临时值来完成此任务。我正在寻找一种不会打破约束的单操作解决方案
注意:这包括(可能)超过两行,并且单个交换不起作用。
如果您仍然不明白这个问题,请考虑聊天频道,当客户端将频道拖动到不同的位置时,我想更新“之前”和“之后”位置“之间”的所有频道位置。
例子: 这里表格有 3 行
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');
现在,假设我想将通道 'ch3' 移动到位置 1,那么 'ch1' 和 'ch2' 的位置将分别更改为 2、3。 但如果我运行这些操作:(假设我已经获得了 ID)
$guildId = 0
$originalPositionOfChannel3 = 3
$newPosition = 0
UPDATE Channel SET position = $newPosition WHERE guildId = $guildId AND name = 'ch3';
UPDATE Channel SET position = position + 1 WHERE guildId = $guildId AND position < $originalPositionOfChannel3 AND position >= $newPosition;```
In MySQL,
I have a table named Channel
(Auto-generated by Prisma ORM)
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;
As you can see, there's a UNIQUE INDEX constraint Channel_guildId_position_key
How can I do something that doesn't break this unique constraint such that: (I can get all the rows with the same guild_id with SELECT * FROM Channel WHERE guildId = $guildId
)
update a channel current
's position field value to x
(assuming x is bigger than current.position
)
update all channels between current.position
and position x
and decrement their position field by 1
update current.position
to position x
Basically, I want to move a channel to a position and everything in between new position and old position needs to advance forward. But I'm getting blocked by the constraint I set which makes (position, guildId)
a unique identifier, and thus requiring a temporary value to accomplish this task. I'm looking for a one-operation solution that doesn't break the constraint
Note: This includes (possibly) more than two rows, and a single swap won't work.
If you still do not understand the question, think of chat channels, when client drags a channel to a different position I want to update all the positions of the channels that are "in between" the "before" and "after" positions.
Example:
Here the table has 3 rows
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');
Now, let's say I want to move channel 'ch3' to position 1, then 'ch1' and 'ch2''s position would be changed to 2, 3 respectively.
But if I run these operations: (Assuming I got the IDs already)
$guildId = 0
$originalPositionOfChannel3 = 3
$newPosition = 0
UPDATE Channel SET position = $newPosition WHERE guildId = $guildId AND name = 'ch3';
UPDATE Channel SET position = position + 1 WHERE guildId = $guildId AND position < $originalPositionOfChannel3 AND position >= $newPosition;```
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论