鉴于下表:
CREATE TABLE IF NOT EXISTS devices_used_by_resource (
id INT NOT NULL,
sourcesId INT NOT NULL,
name VARCHAR(45) NOT NULL,
PRIMARY KEY (id, sourcesId),
INDEX sourcesIdInx (sourcesId ASC),
UNIQUE INDEX nameSourceUniqueInx (name ASC, sourcesId ASC),
CONSTRAINT existingSourcesId
FOREIGN KEY (sourcesId)
REFERENCES sources (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
我希望以下查询:
INSERT INTO devices_used_by_resource(id,sourcesId,name) VALUES(123,321,'the name');
回复:
sourcesId
之前已经过验证。
这是可能的,如果是这样的话?
PS。索引sourcesIdInx是否必需,如果是,为什么?
答案 0 :(得分:1)
不可能按原样使用该语句。违反唯一密钥会引发错误。您必须使用insert ignore
(不允许您对第三个条件作出反应)或使用on duplicate key
来捕获该错误。
如果符合条件,您可以使用会故意抛出错误的on duplicate key
。不幸的是,错误消息与违规行为没有直接关系,它只会是"任何"异常(描述您的情况的异常无论如何都不存在)。在update
- 部分中,检查名称是否不同。如果它没有改变,你什么都不做("忽略"),如果它改变了,你可以设置一个无效的值,例如:扔一个not null
- 错误:
INSERT INTO devices_used_by_resource(id,sourcesId,name)
VALUES(123,321,'the name')
on duplicate key update id = if(name = values(name), id, null);
> 1 row(s) affected
INSERT INTO devices_used_by_resource(id,sourcesId,name)
VALUES(123,321,'the name')
on duplicate key update id = if(name = values(name), id, null);
> 0 row(s) affected
INSERT INTO devices_used_by_resource(id,sourcesId,name)
VALUES(123,321,'the name1')
on duplicate key update id = if(name = values(name), id, null);
> Error Code: 1048. Column 'id' cannot be null
(name, sourcedId)
上有第二个唯一索引,也会触发on duplicate key
。如果插入违反此行的行,您没有指定会发生什么,因此该语句将忽略它(违反(name, sourcedId)
不会更改名称,因此不会抛出异常):
INSERT INTO devices_used_by_resource(id,sourcesId,name)
VALUES(1,321,'the name')
on duplicate key update id = if(name = values(name), id, null);
> 0 row(s) affected
如果您想要抛出异常,也可以比较所有值而不仅仅是名称,因此不同的id
也会引发错误:
INSERT INTO devices_used_by_resource(id,sourcesId,name)
VALUES(123,321,'the name1')
on duplicate key update
id = if(id = values(id) and sourcesId = values(sourcesId)
and name = values(name), id, null);
> Error Code: 1048. Column 'id' cannot be null
异常消息显然不是很清楚错误,因为它引发了一个无关的错误。如果您只想捕获该异常并知道它实际意味着什么,那就没问题了。为了使它更时尚,您可以添加一个触发器,使用id=null
作为指示器来抛出自定义消息,例如
delimiter $$
create trigger trbu_devices_used_by_resource
before update on devices_used_by_resource
for each row
begin
if new.id is null then
SIGNAL SQLSTATE '45000'
SET message_text = 'Inserted duplicate entry with different attributes!';
end if;
end $$
delimiter ;
如果你在没有插入的情况下使用update devices_used_by_resource set id = null
,它也会抛出该错误,但我想这种情况经常不会发生,或者你也可能找到一条覆盖它的消息 - 或者你做一些更复杂的沟通在upsert和触发器之间,例如将id
或sourcesId
设置为-812677
并检查触发器中的值。