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

Fremmednøglekontraint i mange-til-mange forhold

Dette tigger om ballade. Du vil blive ved med at løbe ind i mindre uforeneligheder. Eller ikke engang bemærke dem før meget senere, når skaden er sket. Lad være med at gøre det. Brug også PostgreSQL lokalt. Det er frit tilgængeligt for stort set alle OS. For en person involveret i et "databasekursusprojekt" er dette en overraskende tåbelighed. Relateret:

Andre råd:

  • Som @Priidu nævnt i kommentarerne , dine begrænsninger for fremmednøgle er baglæns. Dette er ikke til debat, de er simpelthen forkerte .

  • Brug en serial i PostgreSQL eller IDENTITY kolonne (Postgres 10+) i stedet for SQLite AUTOINCREMENT . Se:

  • Brug timestamp (eller timestamptz ) i stedet for datetime .

  • Brug ikke id'er med blandede store og små bogstaver.

  • Brug ikke ikke-beskrivende kolonnenavne som id . Nogensinde. Det er et anti-mønster introduceret af halvkloge middleware og ORM'er. Når du slutter dig til et par tabeller, ender du med flere kolonner med navnet id . Det er aktivt sårende.

  • Der er mange navnestile, men de fleste er enige om, at det er bedre at have entalsudtryk som tabelnavne. Det er kortere og mindst lige så intuitivt/logisk. label , ikke labels .

Alt sammen kunne det se sådan ud:

CREATE TABLE IF NOT EXISTS post (
   post_id   serial PRIMARY KEY
 , author_id integer
 , title     text
 , content   text
 , image_url text
 , date      timestamp
);

CREATE TABLE IF NOT EXISTS label (
   label_id  serial PRIMARY KEY
 , name      text UNIQUE
);

CREATE TABLE IF NOT EXISTS label_post(
    post_id  integer REFERENCES post(post_id) ON UPDATE CASCADE ON DELETE CASCADE
  , label_id integer REFERENCES label(label_id) ON UPDATE CASCADE ON DELETE CASCADE
  , PRIMARY KEY (post_id, label_id)
);

Trigger

For at slette ubrugte etiketter skal du implementere en trigger . Jeg leverer en anden version, da jeg ikke er tilfreds med den leveret af @Priidu :

CREATE OR REPLACE FUNCTION f_trg_kill_orphaned_label() 
  RETURNS trigger
  LANGUAGE plpgsql AS
$func$
BEGIN
   DELETE FROM label l
   WHERE  l.label_id = OLD.label_id
   AND    NOT EXISTS (
      SELECT 1 FROM label_post lp
      WHERE  lp.label_id = OLD.label_id
      );
END
$func$;
  • Udløserens funktion skal oprettes før udløseren .

  • En simpel DELETE kommando kan gøre jobbet. Ingen anden forespørgsel nødvendig - især ingen count(*) . EXISTS er billigere.

  • Enkelte anførselstegn omkring sprognavnet tolereres, men det er virkelig en identifikator, så bare udelad vrøvlerne:LANGUAGE plpgsql

CREATE TRIGGER label_post_delaft_kill_orphaned_label
AFTER DELETE ON label_post
FOR EACH ROW EXECUTE PROCEDURE f_trg_kill_orphaned_label();

Der er ingen CREATE OR REPLACE TRIGGER i PostgreSQL, endnu. Bare CREATE TRIGGER .



  1. JSON_DEPTH() – Find den maksimale dybde af et JSON-dokument i MySQL

  2. Får fejl 1822 i MySQL, når du forsøger at oprette en fremmednøgle

  3. Returner JSON fra MySQL med kolonnenavn

  4. Sådan går du gennem session array i php