谷歌的这一结果有点薄,但建议不太可能。
我的具体问题是我需要重新编号两个彼此相关的表中的ID,以便表B中有一个“table_a_id”列。我不能首先对表A重新编号,因为它的B中的子节点指向旧的ID。我不能首先重新编号表B,因为它们会在创建之前指向新的ID。现在重复三到四个表格。
当我可以“启动事务;禁用ref完整性;排除ID;重新启用ref完整性;提交事务”时,我真的不想摆弄个人关系。 Mysql和MSSQL都提供了这个功能IIRC,所以如果Postgres没有,我会感到惊讶。
谢谢!
答案 0 :(得分:48)
你可以做两件事(这些是互补的,而不是替代品):
答案 1 :(得分:33)
我找到了这两个优秀的脚本,它们生成用于删除约束然后重新创建它们的sql。他们在这里:
删除约束
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
重新创建
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;
运行这些查询,输出将是删除和创建约束所需的sql脚本。
删除约束后,您可以使用表格执行所有操作。完成后重新介绍它们。
答案 2 :(得分:17)
似乎不可能。其他建议几乎总是指放弃约束并在工作完成后重新创建它们。
但是,您似乎可以创建约束DEFERRABLE
,以便在事务结束之前不会检查它们。请参阅PostgreSQL documentation for CREATE TABLE
(搜索“deferrable”,它位于页面中间)。
答案 3 :(得分:5)
我认为您需要列出外键约束,删除它们,进行更改,然后再次添加约束。查看alter table drop constraint
和alter table add constraint
。
答案 4 :(得分:5)
这是一个Python脚本,它将删除事务中的所有约束,运行一些查询,然后重新创建所有这些约束。 pg_get_constraintdef
让这非常简单:
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 :(得分:0)
如果约束是DEFERRABLE
,这真的很容易。只需使用事务块并将您的FK约束设置为在事务开始时延迟。
来自http://www.postgresql.org/docs/9.4/static/sql-set-constraints.html:
SET CONSTRAINTS设置当前事务中约束检查的行为。在每个语句的末尾检查IMMEDIATE约束。在事务提交之前不会检查DEFERRED约束。
所以你可以这样做:
BEGIN;
SET CONSTRAINTS
table_1_parent_id_foreign,
table_2_parent_id_foreign,
-- etc
DEFERRED;
-- do all your renumbering
COMMIT;
不幸的是,除非明确设置NOT DEFERRABLE
,否则Postgres似乎会将所有约束默认为DEFERRABLE
。 (我猜这是出于性能原因,但我不确定。)截至Postgres 9.4,如果需要,改变约束以使它们可以延期并不太难:
ALTER TABLE table_1 ALTER CONSTRAINT table_1_parent_id_foreign DEFERRABLE;
(见http://www.postgresql.org/docs/9.4/static/sql-altertable.html。)
我认为这种方法比某些人所描述的更好地删除和重新创建约束,或者在事务结束之前禁用所有(或所有用户)触发器,这需要超级用户权限,如前面{{ 3}}
答案 6 :(得分:-3)
我认为,一个解决方案是创建“临时”列,将您想要的位置关联起来。
使用新列的外键更新值
删除主题栏
将新的“临时”列重命名为相同的名称,然后重命名为inicial的。