Проверка ограничений базы данных, если значения (из разных строк) расположены в последовательном порядке - PullRequest
0 голосов
/ 11 мая 2019

Я настраиваю базу данных 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 для таблицы, в которой хранится информация о пути (какой тип пути и т. Д.).
  • Порядок целое число, которое хранит порядок путевых точек в определенном пути.
  • PrimaryKey является составной из всех трех столбцов.

Ограничение должно проверять, являются ли значения в порядкестолбец (с равным path_id) является последовательным.

Это пример INVALID : (порядок не последовательный, потому что отсутствует 3)

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

Я ожидаю ограничение на не Разрешить вставку этой строки:

 |         104 |       1 |     4 |

Пожалуйста, покажите мне примеры решений для подобных проблем или укажите на документацию о том, как это сделать.

Ответы [ 2 ]

1 голос
/ 11 мая 2019

А вот и вы: 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_id и order, и вы должны знать, что это решение не будет хорошо масштабироваться.

0 голосов
/ 12 мая 2019
  • Ключ-кандидат для этой таблицы (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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...