类似于this question和this 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不返回任何内容,并且不能在子查询中使用。这种直觉正确吗?最佳做法是什么?
答案 0 :(得分:2)
我的猜测是,由于INSERT,因此无法在一个查询中执行此操作 不返回任何内容,不能在子查询中使用。就是它 直觉正确吗?
您可以使用 Trigger (触发)并对表进行一些修改,然后可以通过单个查询来完成。
DROP TRIGGER IF EXISTS add_group_if_not_exists;
DROP TABLE IF EXISTS contact;
DROP TABLE IF EXISTS groups;
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;
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')
;
SELECT * FROM groups;
SELECT contact,group_name FROM contact JOIN groups ON group_reference = groups.id;
结果为:-
1)这些组(请注意,“ NOTASSIGNED”组是上述工作的本质,因此是最初添加的):-
2)与各个组的联系人:-
有效插入
这可能是从这里到永恒的争论,所以我将它留给围栏保姆/破坏者决定:)。但是,一些注意事项:-
这里的最佳做法是什么?
再次围栏。 :)
注意显而易见,但是DROP语句纯粹是为了方便起见,而所有其他SQL 直到INSERT 都运行一次 设置表和触发器以准备单个INSERT 会在必要时添加一个组。