-1

我正在设置一个 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是存储航点坐标的表的 ForeignKey 。
  • path_id是存储有关路径信息(什么类型的路径等)的表的 ForeignKey 。
  • order是一个整数,用于存储特定路径中的航点的顺序。
  • PrimaryKey 是所有 3 列的组合。

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

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

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

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

 |         104 |       1 |     4 |

请向我展示类似问题的解决方案示例,或向我指出如何解决问题的文档。

4

2 回答 2

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并且您必须意识到此解决方案无法很好地扩展这一事实。

于 2019-05-11T18:23:07.930 回答
0
  • 该表的候选键是(track_id, "order"); waypoint_id不需要包括在内。
  • (您可以添加一个额外的唯一约束,(track_id, waypoint_id)以防止在单个轨道上访问点两次)
  • 不需要无间隙约束,您只需要顺序和(每个轨道)唯一性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)
于 2019-05-12T14:44:19.543 回答