唯一约束&mysql和sqlite的插入或更新

btqmn9zl  于 2021-06-20  发布在  Mysql
关注(0)|答案(3)|浏览(404)

我正在寻找一种方法,将一组列定义为唯一的,然后在表中插入一个新条目,或者在列不唯一的情况下更新行。我做了一些研究,找到了一些方法,但是我找不到任何与mysql和sqlite兼容的东西。
假设我有下表:

CREATE TABLE `users` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `uuid` VARCHAR ( 64 ) NOT NULL,
  `name` VARCHAR ( 32 ) NOT NULL,
  `date` BIGINT NULL,
  PRIMARY KEY ( id )
);

我想要 uuid 以及 date 要唯一,以便一个项目可以有多个条目 uuid 或者一个 date ,但不是一种 uuid 以及 date . 我最初想做的是将主键设置为:

PRIMARY KEY ( uuid, date )

但是,由于某些原因,我不能为 date 当你这么做的时候。
我也发现了一些约束,但我不确定这是否有效:

CONSTRAINT user UNIQUE ( `uuid`, `date` )

现在我想在这个表中插入一个新行,但是如果一行具有相同的 uuid 以及 date 已经存在。我找到了一些方法,但它们要么不是我想要的,要么与mysql和sqlite都不兼容: INSERT INTO ... ON DUPLICATE KEY 不适用于sqlite REPLACE INTO 将删除任何我没有指定的内容,而不是更新
我已经做了很长一段时间的研究,但我找不到一个适合我的解决方案。谢谢你的帮助。

zynd9foi

zynd9foi1#

我在google上搜索了几个小时,用mysql和sqlite做了一些测试,我想我找到了一个可行的解决方案。
使…结合 uuid 以及 date unique,我为表添加了一个unique约束。要插入新行或“更新”现有行,我使用 REPLACE INTO ... SELECT .
要创建表:

CREATE TABLE IF NOT EXISTS `users` (
  `id` INT NOT NULL AUTO_INCREMENT, // use INTEGER NOT NULL for SQLite
  `uuid` VARCHAR ( 64 ) NOT NULL,
  `name` VARCHAR ( 32 ) NOT NULL,
  `date` BIGINT NULL,
  CONSTRAINT `uuid_date` UNIQUE ( `uuid`, `date` ),
  PRIMARY KEY ( `id` )
);

这个 CONSTRAINT 将确保 uuid 以及 date 总是独一无二的。
对于插入数据,我使用 REPLACE INTO ... SELECT ,其中我在 SELECT 查询并输入我没有为其指定值的所有列的列名,以确保在替换现有行时保留其值而不是删除它们。

REPLACE INTO `users`
SELECT `id`, `uuid`, ?, `date`
FROM `users` WHERE `uuid` = ? AND `date` = ?;

当然,因为在这种情况下,使用法线时不会丢失任何列 REPLACE INTO ,所以我也可以使用:

REPLACE INTO `users` ( `uuid`, `name`, `date` ) VALUES ( ?, ?, ? );

然而 REPLACE INTO ... SELECT 当我有一个包含更多列的表,并且实际上有一些列在不选择它们时可能会丢失时,查询会很有用。

e0bqpujr

e0bqpujr2#

sqlite解决方案(mysql也应遵循同样的原则)

您只需添加一个唯一索引(至少对于sqlite是这样),就可以:-

DROP TABLE IF EXISTS `users`;
CREATE TABLE IF NOT EXISTS `users` (
  `id` INTEGER, //<<<<<<<<<< See notes below
  `uuid` VARCHAR ( 64 ) NOT NULL,
  `name` VARCHAR ( 32 ) NOT NULL,
  `date` BIGINT NULL,
  PRIMARY KEY ( `id` )
);
CREATE UNIQUE INDEX IF NOT EXISTS uuid_date ON `users` (`uuid`,`date`); //<<<<<<<<<<

注意 AUTO_INCREMENT 导致sqlite失败,因为它不是关键字,sqlite中正确的关键字是 AUTOINCREMENT . 但是,它被省略了,因为它可能不需要作为整数主键(或者通过指定 PRIMARY KEY (id) )如果插入时没有为列提供值,将导致自动生成uniqiue id。
sqlite需要整数,而不是int作为自动生成的id。NOTNULL和unique是隐含的,因此不需要指定它们。
下面是两组示例插入,每一组都复制uuid/日期组合,因此更新而不是插入,并使用相同的uuid但不同的日期插入,反之亦然:-

INSERT OR REPLACE INTO `users` VALUES(null,'Fred01234567','Fred Bloggs the 1st','20180101');
INSERT OR REPLACE INTO `users` VALUES(null,'Fred01234567','Fred Bloggs the 2nd','20180101'); -- <<<< DUPLICATE 
INSERT OR REPLACE INTO `users` VALUES(null,'Fred99999999','Fred Bloggs the 2nd','20180101'); -- <<<< different uuid same date
INSERT OR REPLACE INTO `users` VALUES(null,'Fred01234567','Fred Bloggs the 2nd','99999999'); -- <<<< same uuid different date

INSERT OR REPLACE INTO `users` (`uuid`,'name','date') VALUES('Fred76543210','Fred NotBloggs the 1st','20180202');
INSERT OR REPLACE INTO `users` (`uuid`,'name','date') VALUES('Fred76543210','Fred NotBloggs the 1st','20180202');
INSERT OR REPLACE INTO `users` (`uuid`,'name','date') VALUES('Fred99999999','Fred NotBloggs the 1st','20180202');
INSERT OR REPLACE INTO `users` (`uuid`,'name','date') VALUES('Fred76543210','Fred NotBloggs the 1st','99999999');

SELECT * FROM `users`;

结果如下:-

yquaqz18

yquaqz183#

很抱歉所有的评论。以下是我是如何实现我认为你的目标的。您将丢失users表上作为主键的id。您还必须在表中暂存insert变量。但你会得到你的最终结果。对不起,我没有更好的解决办法。

DROP TABLE users;
DROP TABLE users2;

CREATE TABLE `users` (
`uuid` VARCHAR ( 64 ) NOT NULL,
`name` VARCHAR ( 32 ) NOT NULL,
`date` BIGINT NULL

);

ALTER TABLE `users` ADD PRIMARY KEY(`uuid`,`date`);

INSERT INTO users (`name`,`uuid`,`date`) SELECT '','123','2018-04-01';

CREATE TABLE `users2` (

`uuid` VARCHAR ( 64 ) NOT NULL,
`name` VARCHAR ( 32 ) NOT NULL,
`date` BIGINT NULL

);

INSERT INTO users2 (`name`,`uuid`,`date`) SELECT 'brad','123','2018-04-01';

REPLACE INTO users SELECT `uuid`,`name`,`date` FROM users2 GROUP BY `uuid`,`date`;

SELECT * FROM users;`

相关问题