已复制表上的INSERT查询中的PostgreSQL类型转换失败

时间:2018-07-14 15:41:22

标签: sql django postgresql

我正在尝试将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语句的问题)。

如果有人对我如何强制在类型转换中不做任何修改有任何想法,我将非常感谢。

更新7/16/2018

我遵循了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。因此,我在本地测试然后在我的开发和生产服务器中运行的最终协议是:

  1. SSH进入PostgreSQL Docker容器-运行clear_pulic.sql

  2. 在Django Docker容器中的SSH-运行python manage.py migrate

  3. SSH进入PostgreSQL Docker容器-运行data_migrations.sql

即使跳入和跳出不同的Docker容器,我也要在约30秒内将所有表及其所有数据移植到数据库中。我敢肯定,有更好的方法可以做到这一点,但我对自己的方法感到满意。感谢Gordon Linoff强调了我的SQL的最初缺陷!

更新7/18/2016

请注意,除非您遵循SELECT setval('sometable_id_seq', COALESCE((SELECT MAX(id)+1 FROM sometable),1), false);组查询来重置数据库的ID序列,否则上述方法 会导致ID冲突。

我保留了原始ID值,因为我有一个依赖REST API的开发人员。一般来说,如果您不必这样做,我建议不要包括id字段。

1 个答案:

答案 0 :(得分:1)

列出所有列:

INSERT INTO db_comments_dbcomment ( . . . )
    SELECT . . . 
    FROM dbComments;

这将确保它们按您的期望对齐。