sql >> Database teknologi >  >> RDS >> PostgreSQL

Postgres begrænsning

Det er "let", fordi PostgreSQL er så udvidelsesvenligt. Du kan definere din egen type, sammenligningsoperatorer for typen og en operatorklasse til brug med en btree indeks, så PostgreSQL ved, hvordan man sammenligner dem.

Tricket er at definere "lige" på en sådan måde, at modstridende værdier er ens.

Først definerer vi vores type:

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

Derefter definerer vi en indeksunderstøttelsesrutinebtree indeks ved, hvordan man sammenligner værdierne:

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$$;

Baseret på denne sammenligningsfunktion definerer vi funktioner, der implementerer sammenligningsoperatorerne:

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';

Nu kan vi definere operatorer på vores type:

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 = ~<~
);

Nu er der kun tilbage at definere en operatørklasse der kan bruges til at definere et indeks (dette kræver superbrugerrettigheder):

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);

Nu kan vi definere en tabel, der bruger den nye datatype.

Siden vi definerede tod_ops som standard operatørklasse for typen tod , kan vi oprette en simpel unik begrænsning, og det underliggende indeks vil bruge vores operatørklasse.

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

Lad os teste det:

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.

Er PostgreSQL ikke sejt?




  1. Indsæt i tabel fra Array PHP

  2. Hvorfor UPDATE bruges efter SELECT ændringer 2 rækker i stedet for én?

  3. Valg af en kolonne, der opfylder mange betingelser i forskellige poster

  4. Opretter forbindelse til en MySQL-server ved hjælp af C++