114

In PostgreSQL 8 ist es möglich, den beiden Fremdschlüsseln in der folgenden Tabelle "on delete cascades" hinzuzufügen, ohne diese zu löschen?Wie fügt man "on delete cascade" Einschränkungen hinzu?

# \d pref_scores 
     Table "public.pref_scores" 
Column |   Type   | Modifiers 
---------+-----------------------+----------- 
id  | character varying(32) | 
gid  | integer    | 
money | integer    | not null 
quit | boolean    | 
last_ip | inet     | 
Foreign-key constraints: 
    "pref_scores_gid_fkey" FOREIGN KEY (gid) REFERENCES pref_games(gid) 
    "pref_scores_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 

Beiden referenzierten Tabellen sind unten - hier:

# \d pref_games 
            Table "public.pref_games" 
    Column |   Type    |      Modifiers 
----------+-----------------------------+---------------------------------------------------------- 
gid  | integer      | not null default nextval('pref_games_gid_seq'::regclass) 
rounds | integer      | not null 
finished | timestamp without time zone | default now() 
Indexes: 
    "pref_games_pkey" PRIMARY KEY, btree (gid) 
Referenced by: 
    TABLE "pref_scores" CONSTRAINT "pref_scores_gid_fkey" FOREIGN KEY (gid) REFERENCES pref_games(gid) 

Und hier:

# \d pref_users 
       Table "public.pref_users" 
    Column |   Type    | Modifiers 
------------+-----------------------------+--------------- 
id   | character varying(32)  | not null 
first_name | character varying(64)  | 
last_name | character varying(64)  | 
female  | boolean      | 
avatar  | character varying(128)  | 
city  | character varying(64)  | 
login  | timestamp without time zone | default now() 
last_ip | inet      | 
logout  | timestamp without time zone | 
vip  | timestamp without time zone | 
mail  | character varying(254)  | 
Indexes: 
    "pref_users_pkey" PRIMARY KEY, btree (id) 
Referenced by: 
    TABLE "pref_cards" CONSTRAINT "pref_cards_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_catch" CONSTRAINT "pref_catch_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_chat" CONSTRAINT "pref_chat_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_game" CONSTRAINT "pref_game_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_hand" CONSTRAINT "pref_hand_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_luck" CONSTRAINT "pref_luck_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_match" CONSTRAINT "pref_match_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_misere" CONSTRAINT "pref_misere_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_money" CONSTRAINT "pref_money_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_pass" CONSTRAINT "pref_pass_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_payment" CONSTRAINT "pref_payment_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_rep" CONSTRAINT "pref_rep_author_fkey" FOREIGN KEY (author) REFERENCES pref_users(id) 
    TABLE "pref_rep" CONSTRAINT "pref_rep_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_scores" CONSTRAINT "pref_scores_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_status" CONSTRAINT "pref_status_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 

Und ich frage mich auch, ob es Sinn macht 2 index'es die früheren Tabelle hinzufügen ?

UPDATE: Vielen Dank, und ich habe auch die Beratung bei der Mailing-Liste bekommt, dass ich es in 1 Aussage verwalten konnte und somit keine Notwendigkeit, eine Transaktion:

ALTER TABLE public.pref_scores 
DROP CONSTRAINT pref_scores_gid_fkey, 
ADD CONSTRAINT pref_scores_gid_fkey 
    FOREIGN KEY (gid) 
    REFERENCES pref_games(gid) 
    ON DELETE CASCADE; 
+1

Ein kleiner OT, aber ich habe festgestellt, dass Sie keine Indizes für referenzierende Spalten erstellt haben (zum Beispiel 'pref_scores.gid'). Das Löschen in der referenzierten Tabelle dauert lange ohne diese, wenn Sie viele Zeilen in diesen Tabellen erhalten. Einige Datenbanken erstellen automatisch einen Index für die Referenzspalte (n). PostgreSQL überlässt Ihnen das, da es einige Fälle gibt, in denen es sich nicht lohnt. – kgrittn

+1

Danke! Ich habe tatsächlich bemerkt, dass Löschen dauert lange, aber wusste nicht, dass das der Grund ist –

+1

Welche Fälle wäre das, wenn Indizes auf Fremdschlüssel nicht lohnenswert sind? –

Antwort

144

Ich bin hübsch Sie können nicht einfach on delete cascade zu einer vorhandenen Fremdschlüsseleinschränkung hinzufügen. Sie müssen zuerst die Abhängigkeit löschen und dann die richtige Version hinzufügen. Im Standard-SQL, ich glaube, der einfachste Weg, dies zu tun, um

ist
  • eine Transaktion starten,
  • den Fremdschlüssel fallen,
  • einen Fremdschlüssel mit on delete cascade hinzufügen und schließlich
  • die Transaktion fest

Wiederholen Sie für jeden Fremdschlüssel, den Sie ändern möchten.

PostgreSQL verfügt jedoch über eine nicht standardmäßige Erweiterung, mit der Sie mehrere Integritätsklauseln in einer einzigen SQL-Anweisung verwenden können. Zum Beispiel

alter table public.pref_scores 
drop constraint pref_scores_gid_fkey, 
add constraint pref_scores_gid_fkey 
    foreign key (gid) 
    references pref_games(gid) 
    on delete cascade; 

Wenn Sie nicht den Namen des Fremdschlüssel kennen Sie löschen möchten, können Sie entweder es in pgAdminIII nachschlagen (klicken Sie einfach auf den Tabellennamen und Blick auf die DDL oder erweitern die Hierarchie, bis Sie "Constraints" sehen, oder Sie können query the information schema.

select * 
from information_schema.key_column_usage 
where position_in_unique_constraint is not null 
+0

Danke, das habe ich mir auch gedacht - aber was macht man mit fremden Schlüsseln? Sind das nur Constraints (ähnlich wie NOT NULL), die einfach gelöscht und wieder eingefügt werden können? –

+2

@AlexanderFarber: Ja, sie sind benannte Einschränkungen, die Sie einfach löschen und hinzufügen können. Aber Sie möchten das wahrscheinlich innerhalb einer Transaktion tun. Aktualisierte meine Antwort mit mehr Details. –

+0

+1 zum Suchen nach oben in pgAdminIII. Es gibt Ihnen sogar die Befehle DROP CONSTRAINT und ADD CONSTRAINT, so dass Sie einfach in ein Abfragefenster kopieren und einfügen und den Befehl so bearbeiten können, wie Sie möchten. –

3

Verbrauch:

select replace_foreign_key('user_rates_posts', 'post_id', 'ON DELETE CASCADE'); 

Funktion:

CREATE OR REPLACE FUNCTION 
    replace_foreign_key(f_table VARCHAR, f_column VARCHAR, new_options VARCHAR) 
RETURNS VARCHAR 
AS $$ 
DECLARE constraint_name varchar; 
DECLARE reftable varchar; 
DECLARE refcolumn varchar; 
BEGIN 

SELECT tc.constraint_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name 
FROM 
    information_schema.table_constraints AS tc 
    JOIN information_schema.key_column_usage AS kcu 
     ON tc.constraint_name = kcu.constraint_name 
    JOIN information_schema.constraint_column_usage AS ccu 
     ON ccu.constraint_name = tc.constraint_name 
WHERE constraint_type = 'FOREIGN KEY' 
    AND tc.table_name= f_table AND kcu.column_name= f_column 
INTO constraint_name, reftable, refcolumn; 

EXECUTE 'alter table ' || f_table || ' drop constraint ' || constraint_name || 
', ADD CONSTRAINT ' || constraint_name || ' FOREIGN KEY (' || f_column || ') ' || 
' REFERENCES ' || reftable || '(' || refcolumn || ') ' || new_options || ';'; 

RETURN 'Constraint replaced: ' || constraint_name || ' (' || f_table || '.' || f_column || 
' -> ' || reftable || '.' || refcolumn || '); New options: ' || new_options; 

END; 
$$ LANGUAGE plpgsql; 

Beachten Sie: Diese Funktion wird Eigenschaften der Anfangsfremdschlüssel nicht kopiert werden. Nimmt nur den Namen der fremden Tabelle/Spalte an, löscht den aktuellen Schlüssel und ersetzt durch einen neuen.

Verwandte Themen