我正在尝试将PostgreSQL数据库中的表从Django项目中的一种模式迁移到另一种模式。我删除并重新创建了迁移脚本以整合我的数据库更改,并且该部分可以很好地工作。但是,我在复制数据时遇到问题。
查询
INSERT INTO table_name
SELECT * FROM other_schema.table_name
将工作大约1/4的时间。但是,我经常会收到类似以下的奇数TYPE
错误:
ERROR: column "doc_date" is of type timestamp with time zone but expression
is of type integer LINE 2: SELECT * FROM django_apps.db_comments_dbcomment
然后,我使用CTE分解我的INSERT语句,并像这样键入强制类型转换:
WITH dbComments AS (
SELECT
id,
created_date,
modified_date,
doc_date::TIMESTAMP,
customer_number,
customer_name,
db_table,
db_table_number,
note_processed::BOOLEAN,
note_modified::BOOLEAN,
comment_id,
customer_id,
created_by_id,
modified_by_id
FROM django_apps.db_comments_dbcomment
)
INSERT INTO db_comments_dbcomment
SELECT * FROM dbComments;
但是,我仍然遇到以下错误
ERROR: column "note_modified" is of type boolean but expression
is of type integer LINE 21: SELECT * FROM dbComments;
尽管我已经将该字段强制转换为布尔值(因为我知道BOOLEAN和INTEGER之间的转换是glob SELECT语句的问题)。
如果有人对我如何强制在类型转换中不做任何修改有任何想法,我将非常感谢。
我遵循了Gordon Linoff的建议以及显式类型转换,最终成功了。我只想分享我最终到达那里的方式,以防它对其他人有帮助。
因此,由于此操作的目的是将表迁移到公共模式,所以我首先使用以下查询(clear_public.sql
清除公共模式:
DROP SCHEMA public CASCADE;
CREATE SCHEMA public AUTHORIZATION duser; -- Application user
GRANT ALL ON SCHEMA public TO PUBLIC;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO duser;
然后我只需运行public
,即可在python manage.py migrate
模式中重新创建所有表。
我试图在最终的Django迁移中封装数据传输以运行,但是由于依赖关系,此操作无法实现预期的效果。但是,我使用编写的函数来生成SQL查询并将其转储到SQL文件中(未显示):
def copy_table_data(apps, schema_editor):
"""
Iterating over all our apps and copying data from the django_apps
schema to the newly created tables in the public schema.
"""
# This approach should work for the tables that directly relate to our defined models. IT WILL SKIP TABLES CREATED FOR MANY TO MANY RELATIONS AND OTHER SYSTEM TABLES!
tables = connection.introspection.table_names()
models = connection.introspection.installed_models(tables)
for model in models:
table = model._meta.db_table
vals = ''
cols = ''
for field in model._meta.get_fields():
if hasattr(field, 'column'):
mytype = field.db_type(connection) if hasattr(field, 'db_type') else None
if mytype == None:
pass # fields that do not pertain to an actual column (e.g. One side of ManyToOne relationship)
elif mytype == 'serial':
cols += f', {field.column}' #PostgreSQL don't know serial
vals += f' ,{field.column}'
else:
cols += f', {field.column}'
vals += f' ,{field.column}::{mytype}'
vals = vals[2:] # removing leading comma
cols = cols[2:]
query = f"""
INSERT INTO public.{table} (
{cols}
)
SELECT
{vals}
FROM django_apps.{table};
我用它来生成data_migrations.sql
。因此,我在本地测试然后在我的开发和生产服务器中运行的最终协议是:
SSH进入PostgreSQL Docker容器-运行clear_pulic.sql
在Django Docker容器中的SSH-运行python manage.py migrate
SSH进入PostgreSQL Docker容器-运行data_migrations.sql
即使跳入和跳出不同的Docker容器,我也要在约30秒内将所有表及其所有数据移植到数据库中。我敢肯定,有更好的方法可以做到这一点,但我对自己的方法感到满意。感谢Gordon Linoff强调了我的SQL的最初缺陷!
请注意,除非您遵循SELECT setval('sometable_id_seq', COALESCE((SELECT MAX(id)+1 FROM sometable),1), false);
组查询来重置数据库的ID序列,否则上述方法 会导致ID冲突。
我保留了原始ID值,因为我有一个依赖REST API的开发人员。一般来说,如果您不必这样做,我建议不要包括id
字段。
答案 0 :(得分:1)
列出所有列:
INSERT INTO db_comments_dbcomment ( . . . )
SELECT . . .
FROM dbComments;
这将确保它们按您的期望对齐。