sql >> Databasteknik >  >> RDS >> PostgreSQL

Främmande nyckelkontraint i många-till-många-relationer

Det här är att tigga om problem. Du kommer att fortsätta stöta på mindre inkompatibiliteter. Eller inte ens märka dem förrän långt senare, när skadan är skedd. Gör det inte. Använd PostgreSQL lokalt också. Det är fritt tillgängligt för nästan alla operativsystem. För någon som är involverad i ett "databaskursprojekt" är detta en överraskande dårskap. Relaterat:

Andra råd:

  • Som @Priidu nämnde i kommentarerna , dina främmande nyckelbegränsningar är bakåtriktade. Detta är inte uppe för debatt, de har helt enkelt fel .

  • I PostgreSQL använd en serial eller IDENTITY kolumn (Postgres 10+) istället för SQLite AUTOINCREMENT . Se:

  • Använd timestamp (eller timestamptz ) istället för datetime .

  • Använd inte identifierare med blandade skiftlägen.

  • Använd inte icke-beskrivande kolumnnamn som id . Någonsin. Det är ett antimönster som introducerats av halvvettig middleware och ORM. När du går med i ett par tabeller får du flera kolumner med namnet id . Det är aktivt sårande.

  • Det finns många namngivningsstilar, men de flesta är överens om att det är bättre att ha singulära termer som tabellnamn. Det är kortare och minst lika intuitivt/logiskt. label , inte labels .

Allt tillsammans kan det se ut så här:

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 du vill ta bort oanvända etiketter implementerar du en utlösare . Jag tillhandahåller en annan version eftersom jag inte är nöjd med den som tillhandahålls av @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$;
  • Utlösarens funktion måste skapas före utlösaren .

  • En enkel DELETE kommando kan göra jobbet. Ingen andra fråga behövs - i synnerhet ingen count(*) . EXISTS är billigare.

  • Enkla citattecken runt språknamnet tolereras, men det är egentligen en identifierare, så utelämna bara nonsensen: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();

Det finns ingen CREATE OR REPLACE TRIGGER i PostgreSQL, ännu. Bara CREATE TRIGGER .



  1. Hitta antalet tecken och siffror i en sträng

  2. Villkor för antal associerade poster i SQL

  3. Postgres - samla två kolumner till ett objekt

  4. Fråga efter MySQL:s INFORMATIONSSCHEMA:Varför? På vilket sätt?