使用相同的外键插入多个值
Insert multiple values with the same foreign key
我有两个相互引用的表:
CREATE TABLE Room
room_id INTEGER PRIMARY KEY,
room_name TEXT UNIQUE NOT NULL;
CREATE TABLE Item
item_id INTEGER PRIMARY KEY,
room_id INTEGER,
item_name TEXT,
FOREIGN KEY (room_id) REFERENCES Room (room_id) ON UPDATE RESTRICT ON DELETE RESTRICT;
现在我想添加一个新房间,添加几十个项目进去。
INSERT INTO Room(room_name) VALUES ('Living Room');
假设我不知道有多少个房间,我只想把东西放到客厅里。为此,我需要 select 正确 room_id
。对于单个项目来说,这还算不错:
INSERT INTO Item(room_id, item_name)
SELECT room_id, 'Couch' AS item_name FROM Room WHERE room_name = 'Living Room';
但是如果我想同时插入一堆值怎么办。我尝试使用 last_insert_rowid
,但这并没有将整个 INSERT
视为单个事务。也就是说,最后一个ID一直递增
INSERT INTO Item (room_id, item_name)
VALUES
(last_insert_rowid(), 'Chair'),
(last_insert_rowid(), 'TV'),
(last_insert_rowid(), 'Carpet');
我想避免在每个新行上都使用 SELECT
。有没有办法在 Item
中插入多个值,同时在 Room
中引用最后一个已知的 room_id
?
CROSS JOIN
性质的东西可能非常有用,但我不知道如何让常量在这种情况下表现
我要寻找的最终结果是 Room
看起来像这样:
room_id | room_name
--------+-----------
1 | Living Room
和 Item
像这样:
item_id | room_id | item_name
--------+---------+-----------
1 | 1 | Chair
2 | 1 | TV
3 | 1 | Carpet
您可以使用从新房间获得的 ID 的 CROSS
连接到 CTE,returns 您要插入的项目:
WITH cte(item_name) AS (VALUES ('Chair'), ('TV'), ('Carpet'))
INSERT INTO Item (room_id, item_name)
SELECT r.room_id, c.item_name
FROM Room r CROSS JOIN cte c
WHERE r.room_name = 'Living Room';
参见demo。
如果您使用的 SQLite 版本不支持 CTE,请在子查询中使用 UNION ALL
:
INSERT INTO Item (room_id, item_name)
SELECT r.room_id, c.item_name
FROM Room r
CROSS JOIN (
SELECT 'Chair' item_name UNION ALL
SELECT 'TV' UNION ALL
SELECT 'Carpet'
) c
WHERE r.room_name = 'Living Room';
参见demo。
我有两个相互引用的表:
CREATE TABLE Room
room_id INTEGER PRIMARY KEY,
room_name TEXT UNIQUE NOT NULL;
CREATE TABLE Item
item_id INTEGER PRIMARY KEY,
room_id INTEGER,
item_name TEXT,
FOREIGN KEY (room_id) REFERENCES Room (room_id) ON UPDATE RESTRICT ON DELETE RESTRICT;
现在我想添加一个新房间,添加几十个项目进去。
INSERT INTO Room(room_name) VALUES ('Living Room');
假设我不知道有多少个房间,我只想把东西放到客厅里。为此,我需要 select 正确 room_id
。对于单个项目来说,这还算不错:
INSERT INTO Item(room_id, item_name)
SELECT room_id, 'Couch' AS item_name FROM Room WHERE room_name = 'Living Room';
但是如果我想同时插入一堆值怎么办。我尝试使用 last_insert_rowid
,但这并没有将整个 INSERT
视为单个事务。也就是说,最后一个ID一直递增
INSERT INTO Item (room_id, item_name)
VALUES
(last_insert_rowid(), 'Chair'),
(last_insert_rowid(), 'TV'),
(last_insert_rowid(), 'Carpet');
我想避免在每个新行上都使用 SELECT
。有没有办法在 Item
中插入多个值,同时在 Room
中引用最后一个已知的 room_id
?
CROSS JOIN
性质的东西可能非常有用,但我不知道如何让常量在这种情况下表现
我要寻找的最终结果是 Room
看起来像这样:
room_id | room_name
--------+-----------
1 | Living Room
和 Item
像这样:
item_id | room_id | item_name
--------+---------+-----------
1 | 1 | Chair
2 | 1 | TV
3 | 1 | Carpet
您可以使用从新房间获得的 ID 的 CROSS
连接到 CTE,returns 您要插入的项目:
WITH cte(item_name) AS (VALUES ('Chair'), ('TV'), ('Carpet'))
INSERT INTO Item (room_id, item_name)
SELECT r.room_id, c.item_name
FROM Room r CROSS JOIN cte c
WHERE r.room_name = 'Living Room';
参见demo。
如果您使用的 SQLite 版本不支持 CTE,请在子查询中使用 UNION ALL
:
INSERT INTO Item (room_id, item_name)
SELECT r.room_id, c.item_name
FROM Room r
CROSS JOIN (
SELECT 'Chair' item_name UNION ALL
SELECT 'TV' UNION ALL
SELECT 'Carpet'
) c
WHERE r.room_name = 'Living Room';
参见demo。