sql >> Database >  >> RDS >> PostgreSQL

Foreign key-beperkingen in veel-op-veel-relaties

Dit smeekt om problemen. U blijft kleine onverenigbaarheden tegenkomen. Of merken ze pas veel later op, als er schade is aangericht. Niet doen. Gebruik PostgreSQL ook lokaal. Het is gratis beschikbaar voor bijna elk besturingssysteem. Voor iemand die betrokken is bij een "database cursusproject" is dit een verrassende dwaasheid. Gerelateerd:

Ander advies:

  • Als @Priidu vermeld in de reacties , uw externe sleutelbeperkingen zijn omgekeerd. Dit staat niet ter discussie, ze hebben gewoon ongelijk .

  • Gebruik in PostgreSQL een serial of IDENTITY kolom (Postgres 10+) in plaats van SQLite AUTOINCREMENT . Zie:

  • Gebruik timestamp (of timestamptz ) in plaats van datetime .

  • Gebruik geen hoofdletter-ID's.

  • Gebruik geen niet-beschrijvende kolomnamen zoals id . Ooit. Dat is een anti-patroon geïntroduceerd door half-wit middleware en ORM's. Wanneer je een paar tabellen samenvoegt, krijg je meerdere kolommen met de naam id . Dat is actief kwetsend.

  • Er zijn veel naamgevingsstijlen, maar de meesten zijn het erover eens dat het beter is om enkelvoudige termen als tabelnamen te gebruiken. Het is korter en minstens zo intuïtief/logisch. label , niet labels .

Alles bij elkaar zou het er zo uit kunnen zien:

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

Om ongebruikte labels te verwijderen, implementeert u een trigger . Ik lever een andere versie omdat ik niet tevreden ben met die geleverd door @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$;
  • De trigger functie moet voor worden gemaakt de trigger .

  • Een simpele DELETE commando kan het werk doen. Geen tweede zoekopdracht nodig - in het bijzonder geen count(*) . EXISTS is goedkoper.

  • Enkele aanhalingstekens rond de taalnaam worden getolereerd, maar het is eigenlijk een identifier, dus laat de onzin gewoon weg: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();

Er is geen CREATE OR REPLACE TRIGGER in PostgreSQL, nog niet. Gewoon CREATE TRIGGER .



  1. Gebruiker op de hoogte stellen van databasewijziging? JavaScript/AJAX

  2. MySQL-foutcode:1064. U heeft een fout in uw SQL-syntaxis

  3. Hoe installeer ik SQL Server op een M1 Mac (ARM64)

  4. MySQL join met 3 tafels trick