[英]Moving table columns to new table and referencing as foreign key in PostgreSQL
Suppose we have a DB table with fields假设我们有一个带有字段的数据库表
"id", "category", "subcategory", "brand", "name", "description", etc.
What's a good way of creating separate tables for category
, subcategory
and brand
and the corresponding columns and rows in the original table becoming foreign key references?为category
、 subcategory
和brand
创建单独的表以及原始表中的相应列和行成为外键引用的好方法是什么?
To outline the operations involved:概述所涉及的操作:
In this case, the PostgreSQL DB is accessed via Sequel in a Ruby app, so available interfaces are the command line, Sequel, PGAdmin, etc...在这种情况下,PostgreSQL 数据库是通过 Ruby 应用程序中的 Sequel 访问的,因此可用的接口是命令行、Sequel、PGAdmin 等...
The question: how would you do this?问题:你会怎么做?
-- 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
;
Note: the fragment:注意:片段:
WHERE ins.category = ani.category AND ins.subcategory = ani.subcategory哪里 ins.category = ani.category AND ins.subcategory = ani.subcategory
will lead to problems if these columns contain NULLs.如果这些列包含 NULL,则会导致问题。 It would be better to compare them using最好使用它们进行比较
(ins.category,ins.subcategory) IS NOT DISTINCT FROM (ani.category,ani.subcategory) (ins.category,ins.subcategory) 与 (ani.category,ani.subcategory) 没有区别
I'm not sure I completely understand your question, if this doesn't seem to answer it, then please leave a comment and possibly improve your question to clarify, but it sounds like you want to do a CREATE TABLE xxx AS
.我不确定我是否完全理解你的问题,如果这似乎没有回答它,那么请发表评论并可能改进你的问题以澄清,但听起来你想做一个CREATE TABLE xxx AS
。 For example:例如:
CREATE TABLE category AS (SELECT DISTINCT(category) AS id FROM parent_table);
Then alter the parent_table
to add a foreign key constraint.然后更改parent_table
以添加外键约束。
ALTER TABLE parent_table ADD CONSTRAINT category_fk FOREIGN KEY (category) REFERENCES category (id);
Repeat this for each table you want to create.对要创建的每个表重复此操作。
Here is the related documentation:以下是相关文档:
Note: code and references are for Postgresql 9.4注意:代码和参考适用于 Postgresql 9.4
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.