Comment puis-je désactiver l'intégrité référentielle dans Postgresql 8.2?

les résultats de Google sur celui-ci sont un peu minces, mais suggèrent que ce n'est pas facilement possible.

mon problème spécifique est que je dois renuméroter les ID dans deux tables qui sont liées entre elles de sorte que la table B a une colonne" table_a_id " en elle. Je ne peux pas renuméroter la table A d'abord parce que ses enfants en B pointent vers les vieilles cartes D'identité. Je ne peux pas renuméroter la table B d'abord parce qu'ensuite ils pointeraient vers les nouveaux ID avant qu'ils ne soient créés. Maintenant, répétez l'opération pour les trois ou quatre table.

Je ne veux pas vraiment avoir à tripoter avec les relations individuelles quand je pourrais juste "démarrer la transaction; désactiver l'intégrité ref; trier les IDs; réactiver l'intégrité ref; commit transaction". Mysql et MSSQL fournissent toutes deux cette fonctionnalité IIRC donc je serais surpris que Postgres ne le fasse pas.

Merci!

34
demandé sur gizmo 2008-09-26 18:29:06

7 réponses

cela ne semble pas possible. D'autres suggestions consistent presque toujours à supprimer les contraintes et à les recréer une fois le travail terminé.

cependant, il semble que vous pouvez faire des contraintes DEFERRABLE , de sorte qu'ils ne sont pas vérifiés jusqu'à la fin d'une transaction. Voir documentation PostgreSQL pour CREATE TABLE (rechercher "déférable", c'est au milieu de la page).

16
répondu Joel B Fant 2008-09-26 14:41:22

il y a deux choses que vous pouvez faire (ce sont des solutions complémentaires, pas alternatives):

  • Créez vos contraintes de clé étrangère comme DÉFÉRABLES. Ensuite, appelez " ensemble de contraintes différé;", ce qui fera que les contraintes de clé étrangère ne seront pas vérifiées avant la fin de la transaction. Notez que la valeur par défaut si vous ne spécifiez rien n'est pas DÉFÉRABLE (ce qui est fâcheux).
  • Call " ALTER TABLE mytable DISABLE TRIGGER ALL;", qui empêche toute l'exécution des triggers pendant que vous chargez des données, puis "ALTER TABLE mytable ENABLE TRIGGER ALL;" lorsque vous avez terminé de les réactiver.
48
répondu Nick Johnson 2012-08-23 14:25:02

j'ai trouvé ces 2 excellents scripts qui génèrent le sql pour supprimer les contraintes et ensuite les recréer. les voici:

de l'abandon De la les contraintes

SELECT 'ALTER TABLE "'||nspname||'"."'||relname||'" DROP CONSTRAINT "'||conname||'";'
FROM pg_constraint 
INNER JOIN pg_class ON conrelid=pg_class.oid 
INNER JOIN pg_namespace ON pg_namespace.oid=pg_class.relnamespace 
ORDER BY CASE WHEN contype='f' THEN 0 ELSE 1 END,contype,nspname,relname,conname

pour les recréer

SELECT 'ALTER TABLE "'||nspname||'"."'||relname||'" ADD CONSTRAINT "'||conname||'" '|| pg_get_constraintdef(pg_constraint.oid)||';'
FROM pg_constraint
INNER JOIN pg_class ON conrelid=pg_class.oid
INNER JOIN pg_namespace ON pg_namespace.oid=pg_class.relnamespace
ORDER BY CASE WHEN contype='f' THEN 0 ELSE 1 END DESC,contype DESC,nspname DESC,relname DESC,conname DESC;

Lancez ces requêtes et la sortie sera les scripts sql dont vous avez besoin pour supprimer et créer les contraintes.

une fois que vous laissez tomber les contraintes, vous pouvez faire tout ce que vous voulez avec les tables. Lorsque vous avez terminé de les réintroduire.

32
répondu Dimitris 2017-09-27 16:11:22

je pense que vous avez besoin de faire une liste de vos contraintes clés étrangères, les laisser tomber, faire vos modifications, puis Ajouter les contraintes à nouveau. Consultez la documentation pour alter table drop constraint et alter table add constraint .

5
répondu Liam 2008-09-26 14:43:07

voici un script Python qui supprimera toutes les contraintes d'une transaction, lancera quelques requêtes, puis recréera toutes ces contraintes. pg_get_constraintdef rend ce super-facile:

class no_constraints(object):
    def __init__(self, connection):
        self.connection = connection

    def __enter__(self):
        self.transaction = self.connection.begin()
        try:
            self._drop_constraints()
        except:
            self.transaction.rollback()
            raise

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is not None:
            self.transaction.rollback()
        else:
            try:
                self._create_constraints()
                self.transaction.commit()
            except:
                self.transaction.rollback()
                raise

    def _drop_constraints(self):
        self._constraints = self._all_constraints()

        for schemaname, tablename, name, def_ in self._constraints:
            self.connection.execute('ALTER TABLE "%s.%s" DROP CONSTRAINT %s' % (schemaname, tablename, name))

    def _create_constraints(self):
        for schemaname, tablename, name, def_ in self._constraints:
            self.connection.execute('ALTER TABLE "%s.%s" ADD CONSTRAINT %s %s' % (schamename, tablename, name, def_))

    def _all_constraints(self):
        return self.connection.execute("""
            SELECT n.nspname AS schemaname, c.relname, conname, pg_get_constraintdef(r.oid, false) as condef
                     FROM  pg_constraint r, pg_class c
                     LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
                     WHERE r.contype = 'f'
                    and r.conrelid=c.oid
            """).fetchall()

if __name__ == '__main__':
    # example usage

    from sqlalchemy import create_engine

    engine = create_engine('postgresql://user:pass@host/dbname', echo=True)

    conn = engine.connect()
    with no_contraints(conn):
        r = conn.execute("delete from table1")
        print "%d rows affected" % r.rowcount
        r = conn.execute("delete from table2")
        print "%d rows affected" % r.rowcount
5
répondu zzzeek 2012-01-16 10:43:30

Si les contraintes sont DEFERRABLE , c'est vraiment facile. Il suffit d'utiliser un bloc de transactions et de définir vos contraintes FK à reporter au début de la transaction.

de http://www.postgresql.org/docs/9.4/static/sql-set-constraints.html :

de DÉFINIR des CONTRAINTES définit le comportement de la vérification des contraintes à l'intérieur de la transaction en cours. Les contraintes immédiates sont vérifiées à la fin de chaque déclaration. Les contraintes différées ne sont pas vérifiées tant que la transaction ne s'est pas engagée.

pour que tu puisses faire:

BEGIN;

SET CONSTRAINTS
    table_1_parent_id_foreign, 
    table_2_parent_id_foreign,
    -- etc
DEFERRED;

-- do all your renumbering

COMMIT;

malheureusement, il semble que Postgres renvoie par défaut toutes les contraintes à NOT DEFERRABLE , à moins que DEFERRABLE ne soit explicitement défini. (Je suppose que c'est pour des raisons de performance, mais je ne suis pas sûr.) À partir de Postgres 9.4, il n'est pas trop difficile de modifier les contraintes pour les faire différer si nécessaire:

ALTER TABLE table_1 ALTER CONSTRAINT table_1_parent_id_foreign DEFERRABLE;

(voir ) http://www.postgresql.org/docs/9.4/static/sql-altertable.html .)

je pense que cette approche serait préférable à l'abandon et à la recréation de vos contraintes comme certains l'ont décrit, ou à la désactivation de tous les déclencheurs (ou de tous les utilisateurs) jusqu'à la fin de la transaction, ce qui nécessite des privilèges de superutilisateur, comme indiqué dans un précédent commentaire de @clapas .

0
répondu Sean the Bean 2017-05-23 12:34:15

je pense qu'une solution d'easear serait de créer des colonnes" temporaires " associant où vous voulez qu'elles soient.

mettre à jour les valeurs avec les touches étrangères des nouvelles colonnes

drop the inicial columns

renommer le nouveau "temporaire" des colonnes de même nom, la inicial.

-3
répondu Daniel F 2011-01-24 09:40:34