114

W PostgreSQL 8 można dodawać "na kasowanie kasowania" do obu kluczy obcych w poniższej tabeli bez upuszczania tych ostatnich?Jak dodać ograniczenia "na kasowanie kasowania"?

# \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) 

Obie tablice są przywoływane poniżej - tutaj:

# \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) 

A tutaj:

# \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) 

I również zastanawiam się, czy to ma sens, aby dodać 2 index'es byłego stole ?

UPDATE: Dziękuję i również mam radę na listę mailingową, że mogę zarządzać w 1 oświadczenia, a zatem nie ma potrzeby transakcji:

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

Trochę OT, ale zauważam, że nie utworzono indeksów dla kolumn z odniesieniami (na przykład 'pref_scores.gid'). Usunięcia w przywoływanej tabeli zajmą dużo czasu bez tych, jeśli pojawi się wiele wierszy w tych tabelach. Niektóre bazy danych automatycznie tworzą indeks w kolumnie (kolumnach) odniesienia; PostgreSQL pozostawia ci to, ponieważ są przypadki, w których nie jest to warte zachodu. – kgrittn

+1

Dziękujemy! Zauważyłem, że usuwanie trwa długo, ale nie wiedziałem, że to jest powód. –

+1

Jakie to by były sytuacje, gdy indeksy na obcych kluczach nie są warte zachodu? –

Odpowiedz

144

Jestem całkiem z pewnością nie można po prostu dodać on delete cascade do istniejącego ograniczenia klucza obcego. Najpierw należy usunąć ograniczenie, a następnie dodać poprawną wersję. W standardzie SQL, uważam, że najprostszym sposobem, aby to zrobić jest

  • rozpocząć transakcję,
  • upuść klucz obcy,
  • dodać klucz obcy z on delete cascade, wreszcie
  • zatwierdzić transakcję

Powtórz dla każdego obcego klucza, który chcesz zmienić.

Ale PostgreSQL ma niestandardowe rozszerzenie, które pozwala używać wielu klauzul ograniczających w pojedynczej instrukcji SQL. Na przykład

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; 

Jeśli nie znasz nazwy ograniczenie klucza obcego chcesz usunąć, można też zajrzeć do pgAdminIII (wystarczy kliknąć na nazwę tabeli i spojrzeć na DDL lub rozwiń hierarchii, aż zobaczysz "Ograniczenia"), lub możesz query the information schema.

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

Dzięki, to też myślałem - ale co zrobić z kluczami obcymi? Czy są to po prostu ograniczenia (podobne do NOT NULL), które można łatwo upuszczać i odczytywać? –

+2

@AlexanderFarber: Tak, nazywa się je wiązaniami, które można łatwo upuścić i dodać. Ale prawdopodobnie chcesz to zrobić w ramach transakcji. Zaktualizowałem moją odpowiedź bardziej szczegółowo. –

+0

+1 za sprawdzenie ot w pgAdminIII. Daje nawet polecenia DROP CONSTRAINT i ADD CONSTRAINT, więc możesz po prostu skopiować i wkleić okno zapytania i edytować polecenie do tego, co chcesz. –

3

Zastosowanie:

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

Funkcja:

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; 

Należy pamiętać: Ta funkcja nie skopiuje atrybuty początkowego klucza obcego. Przyjmuje tylko nazwę obcej nazwy tabeli/kolumny, upuszcza bieżący klucz i zastępuje nowym.

Powiązane problemy