我有一张桌子(例如这里简化):
CREATE TABLE msg
(
msg_id VARCHAR(30) NOT NULL,
user_id BIGINT NOT NULL,
message TEXT,
UNIQUE INDEX msg_index (msg_id, user_id);
);
我允许用户使用简单的INSERT INTO添加新消息,如下所示:
INSERT INTO msg (msg_id, user_id, message)
VALUES ($_POST["id"], $user["id"], $_POST["message"]);
一旦有消息,我允许用户创建 Duplicate 。声明非常简单,我可以这样做:
INSERT INTO msg (msg_id, user_id, message)
SELECT CONCAT(msg_id, "_Copy") AS msg_id, user_id, message
WHERE msg_id = $_POST["id"];
第一次工作正常,只有当用户在同一条消息上再次尝试 Duplicate 命令时,才会因UNIQUE INDEX
约束而失败。
有没有办法更改CONTACT()
语句以生成唯一标识符(即“_Copy1”,“_ Copy2”,...)或者我是否必须测试INSERT
是否成功如果没有,请再次尝试下一个可能的条目? (我知道如何做到这一点,我只是想知道MySQL是否提供了令人难以置信的功能,例如自动创建一组独特的列,就像魔术一样!)
答案 0 :(得分:1)
你总是可以使用RAND()
函数来创建随机数(你可以搜索关于如何在MySQL中生成随机字符串的SO),但是我真的不认为它是#sa;好的解决方案。
您的ID应该是唯一的,并且可能会自动递增 添加一个新列可能会好得多,也许" source_msg"这将保存原始邮件的ID(这样您就可以始终知道哪个是用户复制当前邮件的原始邮件)。
如果是"原创"消息 - 只要放在那里0。
表格结构:
CREATE TABLE msg
(
msg_id int NOT NULL AUTO_INCREMENT,
source_msg INT NOT NULL,
user_id BIGINT NOT NULL,
message TEXT,
PRIMARY KEY (ID),
UNIQUE INDEX msg_index (msg_id, user_id);
);
新消息:
INSERT INTO msg (msg_id, source_msg, user_id, message)
VALUES (NULL, 0, $user["id"], $_POST["message"]);
重复留言:
INSERT INTO msg (msg_id, source_msg, user_id, message)
SELECT null, msg_id, user_id, message;
无论如何 - 阅读有关boby table的信息。
答案 1 :(得分:1)
你可以,但它暴露在竞争条件下。因此,它几乎可以一直工作 - 但不是在重载下:
INSERT INTO msg (msg_id, user_id, message)
SELECT (CASE WHEN COUNT(*) = 0 THEN v_msg_id
ELSE CONCAT_WS('_', SUBSTRING_INDEX(v_msg_id, '_', 1), COUNT(*) + 1) AS msg_id,
v_user_id, v_message
FROM msg
WHERE msg_id = v_msg_id;
注意:这假设msg_id
没有下划线。如果可能的话,很容易调整逻辑。
更安全的替代方案是将UUID附加到最后。然而,这非常难看。
答案 2 :(得分:1)
由于“msg_id”是一个字符串,我可能会尝试使用时间戳(以毫秒为单位),因此您将获得一个盒子时间戳,性能(不需要搜索所有以前的副本)和“或多或少”的唯一性如果超过每1秒1000个邮件副本的速度,则会被违反。
INSERT INTO msg (msg_id, user_id, message)
SELECT CONCAT(msg_id, '_', ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000)) AS msg_id,
user_id,
message
WHERE msg_id = $_POST['id'];
注意强>
由于可能的SQL注入,此语法msg_id = $_POST['id'];
非常容易受到攻击。我建议使用占位符,不要直接在查询中传递输入。