我正在寻找一种将一组列定义为唯一的方法,然后在表中插入新条目,或者如果列不是唯一的则更新行。我已经进行了一些研究,找到了解决方法,但是找不到与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
可以有多个条目,但{{1 }}和uuid
。我最初想要做的是将主键设置为这些键:
date
但是,由于某些原因,我在执行此操作时将无法为PRIMARY KEY ( uuid, date )
使用空值。
我还发现了有关约束的一些信息,但不确定是否可行:
date
现在,我想在此表中插入新行,但是如果已经存在具有相同CONSTRAINT user UNIQUE ( `uuid`, `date` )
和uuid
的行,请更新现有行。我发现了几种方法,但是它们要么没有按照我的意愿做,要么与MySQL和SQLite都不兼容:
date
不适用于SQLite INSERT INTO ... ON DUPLICATE KEY
将删除我未指定的所有内容,而不是进行更新我已经进行了一段时间的研究,但是找不到适合我的解决方案。任何帮助表示赞赏。
答案 0 :(得分:1)
您可以简单地添加一个UNIQUE索引(至少对于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
。但是,它被省略了,因为它可能不是必需的,因为如果在插入时未为列提供任何值,则INTEGER PRIMARY KEY(或通过指定PRIMARY KEY (id)
进行隐式)将导致自动生成uniqiue id。
对于自动生成的ID,SQLite需要INTEGER(而不是INT)。隐含NOT NULL和UNIQUE,因此无需指定它们。
这里有两套示例插入,每套都复制了uuid / date组合,从而进行更新,而不是插入,并且也插入了相同的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`;
结果是:-
答案 1 :(得分:1)
我已经搜索了几个小时,并使用MySQL和SQLite进行了一些测试,我认为我找到了一个可行的解决方案。
为了使uuid
和date
的组合唯一,我在表中添加了唯一约束。要插入新行或“更新”现有行,我正在使用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
查询可能会有用,而实际上,如果不选择它们,则可能会丢失列。
答案 2 :(得分:0)
对不起,所有评论。这就是我实现我认为您要追求的目标的方式。您将在用户表上丢失ID作为主键。您还必须将插入变量放在表中。但是,您将获得最终结果。抱歉,我没有更好的解决方案。
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;`