我需要为一行中的两列创建一个唯一约束,并附加冲突策略。假设我们有一张桌子:
CREATE TABLE `telephones`(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
telephone STRING NOT NULL);
因此很显然,它是一个单独的表,用于显示用户与其电话之间的一对多关系。我需要为user_id
和telephone
创建一个唯一索引,因此数据库不应有重复项。
在AFAIK中,有两种创建此类约束的方法:通过将索引创建为单独的SQL请求或通过在CREATE TABLE语句内部创建约束。第一种方式如下:
CREATE UNIQUE INDEX `user_ids_and_telephones` ON `telephones`(`user_id`, `telephone`) ON CONFLICT IGNORE
第二种方式如下:
CREATE TABLE `telephones`(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
telephone STRING NOT NULL,
UNIQUE(`user_id`, `telephone`) ON CONFLICT IGNORE);
我的问题是:这些方法是否等效,并且都可以正确地实现所描述的目标?或者它们是否存在一些逻辑差异,这些差异会影响后续重复插入的逻辑?
我没有发现文档很清晰。
答案 0 :(得分:1)
这两种方式都会创建索引,因此它们以相同的方式起作用(请参见下文)。该文档指出为:-
在大多数情况下,UNIQUE和PRIMARY KEY约束是通过以下方式实现的: 在数据库中创建唯一索引。 (例外是整数 没有ROWID表上的PRIMARY KEY和PRIMARY KEY。)因此, 以下架构在逻辑上是等效的:
CREATE TABLE t1(a, b UNIQUE); CREATE TABLE t1(a, b PRIMARY KEY); CREATE TABLE t1(a, b); CREATE UNIQUE INDEX t1b ON t1(b);
SQL As Understood By SQLite - CREATE TABLE - SQL Data Constraints
但是,我不认为您可以在独立定义索引时编写冲突子句。所以
CREATE UNIQUE INDEX user_ids_and_telephones ON telephones(user_id, telephone) ON CONFLICT IGNORE
无效。
因此,冲突处理将有所不同。
例如,考虑以下内容:-
DROP TABLE IF EXISTS `telephones1`;
CREATE TABLE IF NOT EXISTS `telephones1`(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
telephone STRING NOT NULL);
DROP INDEX IF EXISTS user_ids_and_telephones;
CREATE UNIQUE INDEX `user_ids_and_telephones` ON `telephones1`(`user_id`, `telephone`)
-- ON CONFLICT IGNORE commented out as is invalid
;
DROP TABLE IF EXISTS `telephones2`;
CREATE TABLE IF NOT EXISTS `telephones2`(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
telephone STRING NOT NULL,
UNIQUE(`user_id`, `telephone`) ON CONFLICT IGNORE);
SELECT * FROM sqlite_master WHERE type = 'index' AND name LIKE '%telephones%';
INSERT INTO `telephones2` VALUES
(null,1,'phone1'),(null,2,'phone2'),(null,3,'phone1'),(null,1,'phone1');
INSERT INTO `telephones1` VALUES
(null,1,'phone1'),(null,2,'phone2'),(null,3,'phone1'),(null,1,'phone1');
按照:-
DROP TABLE IF EXISTS `telephones1`
> OK
> Time: 0.389s
CREATE TABLE IF NOT EXISTS `telephones1`(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
telephone STRING NOT NULL)
> OK
> Time: 0.31s
DROP INDEX IF EXISTS user_ids_and_telephones
> OK
> Time: 0s
CREATE UNIQUE INDEX `user_ids_and_telephones` ON `telephones1`(`user_id`, `telephone`)
-- ON CONFLICT IGNORE
> OK
> Time: 0.366s
DROP TABLE IF EXISTS `telephones2`
> OK
> Time: 0.383s
CREATE TABLE IF NOT EXISTS `telephones2`(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
telephone STRING NOT NULL,
UNIQUE(`user_id`, `telephone`) ON CONFLICT IGNORE)
> OK
> Time: 0.358s
SELECT * FROM sqlite_master WHERE type = 'index' AND name LIKE '%telephones%'
> OK
> Time: 0s
INSERT INTO `telephones2` VALUES
(null,1,'phone1'),(null,2,'phone2'),(null,3,'phone1'),(null,1,'phone1')
> Affected rows: 3
> Time: 0.356s
INSERT INTO `telephones1` VALUES
(null,1,'phone1'),(null,2,'phone2'),(null,3,'phone1'),(null,1,'phone1')
> UNIQUE constraint failed: telephones1.user_id, telephones1.telephone
> Time: 0.004s
从slqite_master查询的输出可以看出,实际上创建了两个索引:-
电话2 上的附件是自动生成的索引(即,它以 sqlite_autoindex 开头)