有效地插入行和外部表行(如果不存在)

时间:2019-01-12 00:24:08

标签: sqlite

类似于this questionthis solution for PostgreSQL(尤其是“同时插入缺少的FK行”):

假设我正在使用“组”表和“联系”表制作通讯录。创建新联系人时,我可能希望同时将它们放入组中。所以我可以做:

INSERT INTO Contact VALUES (
  "Bob",
  (SELECT group_id FROM Groups WHERE name = "Friends")
)

但是如果“朋友”组还不存在怎么办?我们可以有效地插入这个新组吗?

显而易见的事情是执行SELECT来测试该组是否已经存在;如果没有,请执行INSERT。然后使用上面的子选择对联系人进行插入。

或者我可以约束Group.name为唯一,执行INSERT或IGNORE,然后使用子SELECT插入到Contacts中。

我还可以保留自己存在哪些组的缓存,但这似乎是我首先在复制数据库的功能。

我的猜测是,无法在一个查询中执行此操作,因为INSERT不返回任何内容,并且不能在子查询中使用。这种直觉正确吗?最佳做法是什么?

1 个答案:

答案 0 :(得分:2)

  

我的猜测是,由于INSERT,因此无法在一个查询中执行此操作   不返回任何内容,不能在子查询中使用。就是它   直觉正确吗?

您可以使用 Trigger (触发)并对表进行一些修改,然后可以通过单个查询来完成。

例如考虑以下问题

纯粹是为了方便制作演示:-

DROP TRIGGER IF EXISTS add_group_if_not_exists;
DROP TABLE IF EXISTS contact;
DROP TABLE IF EXISTS groups;

一次性设置SQL:-

CREATE TABLE IF NOT EXISTS groups (id INTEGER PRIMARY KEY, group_name TEXT UNIQUE);
INSERT INTO groups VALUES(-1,'NOTASSIGNED');
CREATE TABLE IF NOT EXISTS contact (id INTEGER PRIMARY KEY, contact TEXT, group_to_use TEXT, group_reference TEXT DEFAULT -1 REFERENCES groups(id));
CREATE TRIGGER IF NOT EXISTS add_group_if_not_exists 
AFTER INSERT ON contact
BEGIN
 INSERT OR IGNORE INTO groups (group_name) VALUES(new.group_to_use);
 UPDATE contact SET group_reference = (SELECT id FROM groups WHERE group_name = new.group_to_use), group_to_use = NULL WHERE id = new.id;  
END;

将持续使用的SQL:-

INSERT INTO contact (contact,group_to_use) VALUES
        ('Fred','Friends'),
        ('Mary','Family'),
        ('Ivan','Enemies'),
        ('Sue','Work colleagues'),
        ('Arthur','Fellow Rulers'),
        ('Amy','Work colleagues'),
        ('Henry','Fellow Rulers'),
        ('Canute','Fellow Ruler')
;
  • 值的数量和实际值会有所不同。

SQL仅用于演示结果

SELECT * FROM groups;
SELECT contact,group_name FROM contact JOIN groups ON group_reference = groups.id;

结果

结果为:-

1)这些组(请注意,“ NOTASSIGNED”组是上述工作的本质,因此是最初添加的):-

enter image description here

  • 必须谨慎对待错误(例如,“统治者”而不是“统治者”)
  • 使用
  • -1 是因为它不是自动生成的正常值。

2)与各个组的联系人:-

enter image description here

  

有效插入

这可能是从这里到永恒的争论,所以我将它留给围栏保姆/破坏者决定:)。但是,一些注意事项:-

  • 它可以工作并且似乎可以完成所需的工作。
  • 由于增加了浪费的列,因此有点浪费。
  • 它试图通过将列更改为空字符串来最大程度地减少浪费(NULL可能更有效,但对于某些情况可能会造成混淆)
  • 与可能忽略不计的替代方案相比,显然会有开销BUT(如果您要提取每个Facebook用户,则可能很重要),但是如果由用户输入驱动,则可能无关紧要。
  

这里的最佳做法是什么?

再次围栏。 :)

  

注意显而易见,但是DROP语句纯粹是为了方便起见,而所有其他SQL 直到INSERT 都运行一次   设置表和触发器以准备单个INSERT   会在必要时添加一个组。