PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Ograniczenie Postgresa

Jest to „łatwe”, ponieważ PostgreSQL jest tak rozszerzalny. Możesz zdefiniować swój własny typ, operatory porównania dla typu i klasę operatora do użycia z btree indeks, aby PostgreSQL wiedział, jak je porównywać.

Sztuką jest zdefiniowanie „równości” w taki sposób, aby sprzeczne wartości były równe.

Najpierw definiujemy nasz typ:

CREATE TYPE tod AS ENUM ('morning', 'afternoon', 'anytime');

Następnie definiujemy procedurę obsługi indeksów tak, że btree indeks wie, jak porównać wartości:

CREATE FUNCTION tod_compare(tod, tod) RETURNS integer
   IMMUTABLE LANGUAGE sql AS
$$SELECT CASE WHEN $1 = 'morning' AND $2 = 'afternoon' THEN -1
            WHEN $1 = 'afternoon' AND $2 = 'morning' THEN 1
            ELSE 0
       END$$;

Na podstawie tej funkcji porównania definiujemy funkcje, które implementują operatory porównania:

CREATE FUNCTION tod_eq(tod, tod) RETURNS boolean IMMUTABLE LANGUAGE sql
   AS 'SELECT tod_compare($1, $2) = 0';

CREATE FUNCTION tod_lt(tod, tod) RETURNS boolean IMMUTABLE LANGUAGE sql
   AS 'SELECT tod_compare($1, $2) = -1';

CREATE FUNCTION tod_le(tod, tod) RETURNS boolean IMMUTABLE LANGUAGE sql
   AS 'SELECT tod_compare($1, $2) <= 0';

CREATE FUNCTION tod_ge(tod, tod) RETURNS boolean IMMUTABLE LANGUAGE sql
   AS 'SELECT tod_compare($1, $2) >= 0';

CREATE FUNCTION tod_gt(tod, tod) RETURNS boolean IMMUTABLE LANGUAGE sql
   AS 'SELECT tod_compare($1, $2) = 1';

CREATE FUNCTION tod_ne(tod, tod) RETURNS boolean IMMUTABLE LANGUAGE sql
   AS 'SELECT tod_compare($1, $2) <> 0';

Teraz możemy zdefiniować operatory na naszym typie:

CREATE OPERATOR ~=~ (
   PROCEDURE = tod_eq,
   LEFTARG = tod,
   RIGHTARG = tod,
   COMMUTATOR = ~=~,
   NEGATOR = ~<>~
);

CREATE OPERATOR ~<>~ (
   PROCEDURE = tod_ne,
   LEFTARG = tod,
   RIGHTARG = tod,
   COMMUTATOR = ~<>~,
   NEGATOR = ~=~
);

CREATE OPERATOR ~<=~ (
   PROCEDURE = tod_le,
   LEFTARG = tod,
   RIGHTARG = tod,
   COMMUTATOR = ~>=~,
   NEGATOR = ~>~
); 

CREATE OPERATOR ~<~ (
   PROCEDURE = tod_lt,
   LEFTARG = tod,
   RIGHTARG = tod,
   COMMUTATOR = ~>~,
   NEGATOR = ~>=~
);

CREATE OPERATOR ~>~ (
   PROCEDURE = tod_gt,
   LEFTARG = tod,
   RIGHTARG = tod,
   COMMUTATOR = ~<~,
   NEGATOR = ~<=~
);

CREATE OPERATOR ~>=~ (
   PROCEDURE = tod_ge,
   LEFTARG = tod,
   RIGHTARG = tod,
   COMMUTATOR = ~<=~,
   NEGATOR = ~<~
);

Teraz pozostaje tylko zdefiniować klasę operatora które mogą być użyte do zdefiniowania indeksu (wymaga to uprawnień superużytkownika):

CREATE OPERATOR CLASS tod_ops DEFAULT FOR TYPE tod USING btree AS
   OPERATOR 1 ~<~(tod,tod),
   OPERATOR 2 ~<=~(tod,tod),
   OPERATOR 3 ~=~(tod,tod),
   OPERATOR 4 ~>=~(tod,tod),
   OPERATOR 5 ~>~(tod,tod),
   FUNCTION 1 tod_compare(tod,tod);

Teraz możemy zdefiniować tabelę, która używa nowego typu danych.

Ponieważ zdefiniowaliśmy tod_ops jako domyślną klasę operatora dla typu tod , możemy utworzyć proste ograniczenie unikatowe, a bazowy indeks użyje naszej klasy operatora.

CREATE TABLE schedule (
   id integer PRIMARY KEY,
   day date NOT NULL,
   time_of_day tod NOT NULL,
   UNIQUE (day, time_of_day)
);

Przetestujmy to:

INSERT INTO schedule VALUES (1, '2018-05-01', 'morning');

INSERT INTO schedule VALUES (2, '2018-05-01', 'afternoon');

INSERT INTO schedule VALUES (3, '2018-05-02', 'anytime');

INSERT INTO schedule VALUES (4, '2018-05-02', 'morning');
ERROR:  duplicate key value violates unique constraint "schedule_day_time_of_day_key"
DETAIL:  Key (day, time_of_day)=(2018-05-02, morning) already exists.

Czy PostgreSQL nie jest fajny?




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Po przywróceniu PostgreSQL otrzymuję odmowę uprawnień dla relacji django_session

  2. Błąd Postgres bytea podczas wiązania wartości null z przygotowanymi instrukcjami

  3. Funkcja PostgreSQl zwraca wiele dynamicznych zestawów wyników

  4. Django emuluje zachowanie wyzwalacza bazy danych podczas zbiorczego wstawiania/aktualizowania/usuwania

  5. PostgreSQL usuwa wszystkie rekordy oprócz najstarszych