SQL:如何检查外键是否真的发生了变化

时间:2013-12-26 13:25:36

标签: sql postgresql plpgsql

我让FK遇到了错误的限制,我必须改变它:

ALTER TABLE user_login_logout_fact DROP CONSTRAINT user_fk;

ALTER TABLE user_login_logout_fact
  ADD CONSTRAINT user_fk FOREIGN KEY (user_id)
      REFERENCES uuser (id) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;

它没有问题,但我必须使用补丁文件来应用它,并检查它是否已经应用。所以我必须创建这样的函数:

CREATE FUNCTION tryUpgrade(patch varchar) RETURNS integer AS $$
    DECLARE testRecord RECORD;
    BEGIN
        RAISE NOTICE 'checking %', patch;
        SELECT INTO testRecord * FROM patchlog where basename = patch;
        IF FOUND THEN
            RAISE NOTICE 'patch % has already been applied', patch;
            RETURN 0;
        END IF;

    //check if constraints are ok
    IF ok THEN
        RAISE NOTICE 'upgraded but not noted';
        INSERT INTO patchlog VALUES (patch, now());
        RETURN 0;
    END IF;

    SELECT INTO testRecord upgrade(); //this function will alter table
    INSERT INTO patchlog VALUES (patch, now());
    RAISE NOTICE 'upgraded';
    RETURN 1;
END;
$$ LANGUAGE plpgsql;

所以,问题是 - 如何检查FK是否会使用ON DELETE CASCADE而不是旧的NO ACTION?

2 个答案:

答案 0 :(得分:1)

  

如何检查FK是否使用ON DELETE CASCADE而不是旧的NO ACTION?

您可以查看系统目录表pg_constraint中的confdeltype。我引用手册:

  

外键删除操作代码:a =无操作,r = restrict,c = cascade,n =设置null,d =设置默认值

使用它像:

IF EXISTS (
   SELECT 1
   FROM   pg_constraint
   WHERE  conname = 'user_fk'
   AND    conrelid = 'user_login_logout_fact'::regclass
   AND    confdeltype = 'c'
  ) THEN 
  -- all done
ELSE
  -- run ALTER TABLE ...
END IF;

表名可以选择是模式限定的。详情:
How do I speed up counting rows in a PostgreSQL table?

信息模式与系统目录

当你自己回答时,可以通过查询符合SQL标准的information schema来实现同样的目标。

然而:

  • 并非所有主要的RDBMS都实现它。例如,甲骨文没有。

  • 信息模式是通过(有时非常复杂的) 视图 (而不是表格)来实现的,这使得查找很多比直接访问pg_catalog中的表格要慢。实际数据库中的快速测试显示了手头示例的因子10。我似乎有1000倍以上。

  • 使用信息模式的目的通常是使您的实现“可移植”。但这几乎从未开始。各种RDBMS在很多方面都远离SQL标准。

还有另一个好处:Postgres不会在主要版本的pg_catalog中声明有关表格结构的任何内容。通过使用信息模式,可以在Postgres本身的主要版本上保持安全 但是,基本结构几乎没有变化。虽然可能,但这样的查询在将来的版本中会破坏,这是不太可能的。

答案 1 :(得分:1)

此外,第二个解决方案似乎更少特定于postgresql。

有关referential_constraints表中的外键存储的信息:

SELECT * FROM information_schema.referential_constraints 
WHERE CAST(constraint_name AS TEXT) LIKE 'user_fk' 
    AND delete_rule LIKE 'CASCADE' 
    AND update_rule LIKE 'CASCADE';