如何使用PostgreSQL中的ALTER TABLE将外键约束添加到同一个表

时间:2013-06-29 09:55:40

标签: postgresql foreign-keys alter-table

要创建我使用的表:

CREATE TABLE category
(
  cat_id serial NOT NULL,
  cat_name character varying NOT NULL,
  parent_id integer NOT NULL,
  CONSTRAINT cat_id PRIMARY KEY (cat_id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE category
  OWNER TO pgsql;

parent_id是另一个类别的ID。现在我有一个问题:如何与其子级级联删除记录?我需要将parent_id设置为cat_id的外键。 我试试这个:

  ALTER TABLE category 
ADD CONSTRAINT cat_cat_id_fkey FOREIGN KEY (parent_id)
      REFERENCES category (cat_id) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE CASCADE

但它落在:

ERROR:  insert or update on table "category" violates foreign key constraint "cat_cat_id_fkey"
DETAIL:  Key (parent_id)=(0) is not present in table "category".

3 个答案:

答案 0 :(得分:6)

您遇到的问题 - 层次结构顶部类别的parent_id是什么?

如果它是null - 它会破坏NOT NULL constratint。

如果它是某个任意数字,如0 - 它将破坏外键(如您的示例中所示)。

常见解决方案 - 将NOT NULL constratint放在parent_id上,并将parent_id设置为null以获取最高类别。

答案 1 :(得分:3)

-- create some fake data for testing
--
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE category

(
  cat_id serial NOT NULL,
  cat_name character varying NOT NULL,
  parent_id integer NOT NULL,
  CONSTRAINT cat_id PRIMARY KEY (cat_id)
);

INSERT INTO category(cat_name,parent_id)
SELECT 'Name_' || gs::text
        , gs % 3
FROM generate_series(0,9) gs
        ;

        -- find the records with the non-existing parents
SELECT ca.parent_id , COUNT(*)
FROM category ca
WHERE NOT EXISTS (
        SELECT *
        FROM category nx
        WHERE nx.cat_id = ca.parent_id
        )
GROUP BY ca.parent_id
        ;

        -- if all is well: proceed
        -- make parent pointer nullable
ALTER TABLE category
        ALTER COLUMN parent_id DROP NOT NULL
        ;

        -- set non-existing parent pointers to NULL
UPDATE category ca
SET parent_id = NULL
WHERE NOT EXISTS (
        SELECT *
        FROM category nx
        WHERE nx.cat_id = ca.parent_id
        )
        ;

        -- Finally, add the FK constraint
ALTER TABLE category
        ADD CONSTRAINT cat_cat_id_fkey FOREIGN KEY (parent_id)
              REFERENCES category (cat_id) MATCH SIMPLE
              ON UPDATE CASCADE ON DELETE CASCADE
        ;

答案 2 :(得分:1)

这很简单 外键parent_id指的是cat_id 此处存在parent_id=0的记录,但不存在cat_id=0的记录。