我正在try 编写一个允许您在建筑物中插入新房间的查询,但如果该建筑物ID不存在,则会失败

            INSERT INTO room (
                building_id, room_name
            ) VALUES (
                $1, 
                CONCAT('Room ', (SELECT count(1) +1 FROM room WHERE building_id = $1))
            )
            RETURNING building_id, id, room_name, version

目前,您可以使用任何随机的建筑物ID进行插入,结果将是房间表中的垃圾数据和大量带有不存在的建筑物ID的Room 1个条目.

try 这样的操作(显然是在事务中)是可行的,但是如果在插入发生之前,在SELECT运行之后,建筑被删除了,会发生什么呢?

            INSERT INTO room (
                building_id, 
                room_name
            ) 
            SELECT 
                $1, 
                CONCAT(
                    'Room ',
                    (SELECT count(1) + 1
                    FROM room AS r 
                    WHERE r.building_id = $1)
                )
            FROM building AS b
            WHERE b.id = $1
            RETURNING building_id, id, room_name, version

虽然这不太可能,但我仍然好奇它是否可以避免. 是否可以改进此查询以完全避免此类并发问题,或者是否有一种方法可以使用外键强制房间插入在事务提交时始终具有有效的Building_id,或者其他一些新的解决方案?

推荐答案

如果建筑不存在,简单的约束将阻止插入房间.

try 添加一个约束--这样的约束会给您提供一些可以测试的东西.

CREATE TABLE building(
    id int UNIQUE, 
    name varchar(15)
);

CREATE TABLE room(
    id int UNIQUE, 
    building_id int, 
    name varchar(10),
    CONSTRAINT foreign_key_room_building
        FOREIGN KEY(building_id) 
        REFERENCES building(id)
        ON DELETE CASCADE,
    CONSTRAINT unique_id_building_id
        UNIQUE (id, building_id)    
);

INSERT INTO building
    (id, name)
VALUES
    (1, 'orange building'),
    (2, 'red building')
;
     
INSERT INTO room
    (id, building_id, name)
VALUES
    (1, 1, 'front room'),
    (2, 1, 'back room')
;

则以下代码将失败.

INSERT INTO room
    (id, building_id, name)
VALUES
    (3, 3, 'front room')
;

这导致了错误

ERROR: insert or update on table "room" violates foreign key constraint "foreign_key_room_building" Detail: Key (building_id)=(3) is not present in table "building".

以下是一个可供使用的SQLFdle链接: http://sqlfiddle.com/#!17/babbf7/1

Sql相关问答推荐

当编号和版本的唯一状态更改时报告

如何在一个范围内进行分组.""范围值在范围表中定义

如何在Snowflake SQL存储过程中传递LIMIT和OFFSET的参数?

通过 Select 值的顺序进行排序ClickHouse

如何优化我的功能以减少花费的时间?

使用Kotlin Exposed SQL DSL Select 多个值并排序

如何将我的联接数据放入每个用户每月多行的列中?

具有多个条件的SQL否定

Postgres SQL查询从字符串中获取邮箱地址

Proc SQL Select Distinct SAS

如何使用SQL生成数据的滚动3天总和

从输出中删除 jsonb_build_object

根据要过滤的列的值进行联接和分组

计算 ID 满足条件的次数

达到特定值时,从0开始累加求和

使用给定的变量对在循环中执行更新语句

如何在 DAX 中通过 Window 函数应用订单

添加一列并根据其他列值进行填充

在 BigQuery 数据集中查找表大小和占总数据集大小的百分比

如何跨行合并以删除 SQL 中的空值?