将 table 列移动到新的 table 并在 PostgreSQL 中作为外键引用
Moving table columns to new table and referencing as foreign key in PostgreSQL
假设我们有一个 DB table 字段
"id", "category", "subcategory", "brand", "name", "description", etc.
创建单独的 table 的好方法是什么
category
、subcategory
和 brand
并且原始 table 中的相应列和行成为外键引用?
概述涉及的操作:
- 获取原始table每一列中的所有唯一值,这些值应该成为外键;
- 为那些
创建tables
- 在原始 table(或副本)
中创建外键引用列
在这种情况下,在 Ruby 应用程序中通过 Sequel 访问 PostgreSQL 数据库,因此可用的界面是命令行、Sequel、PGAdmin 等...
问题:你会怎么做?
我不确定我是否完全理解你的问题,如果这似乎不能回答它,那么请发表评论并可能改进你的问题以澄清,但听起来你想做一个 CREATE TABLE xxx AS
。例如:
CREATE TABLE category AS (SELECT DISTINCT(category) AS id FROM parent_table);
然后修改 parent_table
添加外键约束。
ALTER TABLE parent_table ADD CONSTRAINT category_fk FOREIGN KEY (category) REFERENCES category (id);
对每个要创建的 table 重复此操作。
这里是相关文档:
注意:代码和参考资料适用于 Postgresql 9.4
-- Some test data
CREATE TABLE animals
( id SERIAL NOT NULL PRIMARY KEY
, name varchar
, category varchar
, subcategory varchar
);
INSERT INTO animals(name, category, subcategory) VALUES
( 'Chimpanzee' , 'mammals', 'apes' )
,( 'Urang Utang' , 'mammals', 'apes' )
,( 'Homo Sapiens' , 'mammals', 'apes' )
,( 'Mouse' , 'mammals', 'rodents' )
,( 'Rat' , 'mammals', 'rodents' )
;
-- [empty] table to contain the "squeezed out" domain
CREATE TABLE categories
( id SERIAL NOT NULL PRIMARY KEY
, category varchar
, subcategory varchar
, UNIQUE (category,subcategory)
);
-- The original table needs a "link" to the new table
ALTER TABLE animals
ADD column category_id INTEGER -- NOT NULL
REFERENCES categories(id)
;
-- FK constraints are helped a lot by a supportive index.
CREATE INDEX animals_categories_fk ON animals (category_id);
-- Chained query to:
-- * populate the domain table
-- * initialize the FK column in the original table
WITH ins AS (
INSERT INTO categories(category, subcategory)
SELECT DISTINCT a.category, a.subcategory
FROM animals a
RETURNING *
)
UPDATE animals ani
SET category_id = ins.id
FROM ins
WHERE ins.category = ani.category
AND ins.subcategory = ani.subcategory
;
-- Now that we have the FK pointing to the new table,
-- we can drop the redundant columns.
ALTER TABLE animals DROP COLUMN category, DROP COLUMN subcategory;
-- show it to the world
SELECT a.*
, c.category, c.subcategory
FROM animals a
JOIN categories c ON c.id = a.category_id
;
注:片段:
WHERE ins.category = ani.category
AND ins.subcategory = ani.subcategory
如果这些列包含 NULL,将会导致问题。
最好使用
来比较它们
(ins.category,ins.subcategory)
IS NOT DISTINCT FROM
(ani.category,ani.subcategory)
假设我们有一个 DB table 字段
"id", "category", "subcategory", "brand", "name", "description", etc.
创建单独的 table 的好方法是什么
category
、subcategory
和 brand
并且原始 table 中的相应列和行成为外键引用?
概述涉及的操作:
- 获取原始table每一列中的所有唯一值,这些值应该成为外键;
- 为那些 创建tables
- 在原始 table(或副本) 中创建外键引用列
在这种情况下,在 Ruby 应用程序中通过 Sequel 访问 PostgreSQL 数据库,因此可用的界面是命令行、Sequel、PGAdmin 等...
问题:你会怎么做?
我不确定我是否完全理解你的问题,如果这似乎不能回答它,那么请发表评论并可能改进你的问题以澄清,但听起来你想做一个 CREATE TABLE xxx AS
。例如:
CREATE TABLE category AS (SELECT DISTINCT(category) AS id FROM parent_table);
然后修改 parent_table
添加外键约束。
ALTER TABLE parent_table ADD CONSTRAINT category_fk FOREIGN KEY (category) REFERENCES category (id);
对每个要创建的 table 重复此操作。
这里是相关文档:
注意:代码和参考资料适用于 Postgresql 9.4
-- Some test data
CREATE TABLE animals
( id SERIAL NOT NULL PRIMARY KEY
, name varchar
, category varchar
, subcategory varchar
);
INSERT INTO animals(name, category, subcategory) VALUES
( 'Chimpanzee' , 'mammals', 'apes' )
,( 'Urang Utang' , 'mammals', 'apes' )
,( 'Homo Sapiens' , 'mammals', 'apes' )
,( 'Mouse' , 'mammals', 'rodents' )
,( 'Rat' , 'mammals', 'rodents' )
;
-- [empty] table to contain the "squeezed out" domain
CREATE TABLE categories
( id SERIAL NOT NULL PRIMARY KEY
, category varchar
, subcategory varchar
, UNIQUE (category,subcategory)
);
-- The original table needs a "link" to the new table
ALTER TABLE animals
ADD column category_id INTEGER -- NOT NULL
REFERENCES categories(id)
;
-- FK constraints are helped a lot by a supportive index.
CREATE INDEX animals_categories_fk ON animals (category_id);
-- Chained query to:
-- * populate the domain table
-- * initialize the FK column in the original table
WITH ins AS (
INSERT INTO categories(category, subcategory)
SELECT DISTINCT a.category, a.subcategory
FROM animals a
RETURNING *
)
UPDATE animals ani
SET category_id = ins.id
FROM ins
WHERE ins.category = ani.category
AND ins.subcategory = ani.subcategory
;
-- Now that we have the FK pointing to the new table,
-- we can drop the redundant columns.
ALTER TABLE animals DROP COLUMN category, DROP COLUMN subcategory;
-- show it to the world
SELECT a.*
, c.category, c.subcategory
FROM animals a
JOIN categories c ON c.id = a.category_id
;
注:片段:
WHERE ins.category = ani.category AND ins.subcategory = ani.subcategory
如果这些列包含 NULL,将会导致问题。 最好使用
来比较它们(ins.category,ins.subcategory) IS NOT DISTINCT FROM (ani.category,ani.subcategory)