数据库约束检查(不同行中的)值是否连续

时间:2019-05-11 13:30:19

标签: database postgresql constraints

我正在建立一个PostgreSQL数据库,并希望创建一个约束来检查值(来自单个表中不同行的值)是否连续。

该表如下所示:

+-------------+---------+-------+
| waypoint_id | path_id | order |
+-------------+---------+-------+
|          89 |       1 |     1 |
|          16 |       1 |     2 |
|          17 |       1 |     3 |
|          19 |       1 |     4 |
|           4 |       1 |     5 |
|          75 |       2 |     1 |
|          28 |       2 |     2 |
|           2 |       2 |     3 |
+-------------+---------+-------+

这是一个表,用于存储特定路径的路点顺序。

  • waypoint_id 是表的外键,其中 航路点已存储。
  • path_id 是表的外键,其中有关 路径已存储(路径的类型等)。
  • 订单是一个整数,用于存储特定路径中航路点的顺序。
  • PrimaryKey是所有3列的组合。

约束必须检查order列(具有相同的path_id)中的值是否连续。

这是一个无效示例:(该顺序不连续,因为缺少3个)

+-------------+---------+-------+
| waypoint_id | path_id | order |
+-------------+---------+-------+
|          21 |       1 |     1 |
|          29 |       1 |     2 |
|         104 |       1 |     4 |
+-------------+---------+-------+

我希望约束不允许允许该行的插入:

 |         104 |       1 |     4 |

请向我展示类似问题的解决方案示例,或向我介绍有关如何解决该问题的文档。

2 个答案:

答案 0 :(得分:1)

您在这里:https://dbfiddle.uk/?rdbms=postgres_11&fiddle=b67be9527e86fd444d158f9ab93bf600

对于急躁的人:

CREATE OR REPLACE FUNCTION consecutive_check()
    RETURNS trigger
    LANGUAGE plpgsql
AS $function$
BEGIN
    IF NEW."order" = 1 OR EXISTS (SELECT 1 FROM my_table WHERE path_id = NEW.path_id AND "order" = (NEW."order" - 1)) THEN
        RETURN NEW;
    END IF;

    RAISE EXCEPTION 'Previous waypoint not available for path_id = %', NEW.path_id;
END;
$function$;

CREATE TRIGGER no_holes_path
    BEFORE INSERT
    ON my_table
    FOR EACH ROW
    EXECUTE PROCEDURE consecutive_check()
;

警告:这将导致查询表,因此您必须path_idorder上有一个索引,并且您必须注意以下事实:该解决方案无法很好地扩展。

答案 1 :(得分:0)

  • 该表的候选键为(track_id, "order")waypoint_id不需要包括在内。
  • (您可以在(track_id, waypoint_id)上添加一个额外的唯一约束,以防止在单个轨道上两次访问点)
  • 不需要 gapless 约束,您只需要order
  • 上的顺序和(每磁道)唯一性
  • ORDER是关键字;最好避免将其用作标识符。

CREATE TABLE tracks
        (track_id INTEGER NOT NULL
        , step INTEGER NOT NULL
        , waypoint_id INTEGER -- REFERENCES waypoints(id)
        , PRIMARY KEY (track_id,step)
        );

INSERT INTO tracks(track_id, step, waypoint_id)VALUES
(1,1,89) , (1,2,16) , (1,4,17), (1,5,19), (1,6,4)       -- mind the gap!
, (2,11,75) , (2,22,28) , (2,44,2)                      -- Large gaps!
        ;

CREATE VIEW tracks_ordered AS
SELECT track_id
        , rank() OVER (PARTITION BY track_id ORDER BY step) AS "Order!"
        , waypoint_id
FROM tracks;

SELECT *FROM tracks_ordered;

结果:


 track_id | Order! | waypoint_id 
----------+--------+-------------
        1 |      1 |          89
        1 |      2 |          16
        1 |      3 |          17
        1 |      4 |          19
        1 |      5 |           4
        2 |      1 |          75
        2 |      2 |          28
        2 |      3 |           2
(8 rows)