簡體   English   中英

從 csv 復制時,復制命令不會更新 Id_sequence 列將錯誤拋出到列“id”中的空值違反非空約束

[英]Copy command doesnt update the Id_sequence column when copying from csv throws error to null value in column "id" violates not-null constraint

我有 csv 文件,必須將數據復制到 postgre 表,如果在我的 csv 中,如果我不輸入 Id 和 Updated_at 的數據會拋出錯誤,但它不應該因為 id 被標記為默認值和增量。 我正在從 python 做這個副本

錯誤:

2019-12-01T14:05:16.57+0530 [APP/PROC/WEB/0] OUT 錯誤代碼:23502。錯誤錯誤:“id”列中的空值違反了非空約束 2019-12-01T14:05:16.57 +0530 [APP/PROC/WEB/0] OUT DETAIL:失敗的行包含(null,street_address,null)。
2019-12-01T14:05:16.57+0530 [APP/PROC/WEB/0] OUT CONTEXT:復制人口統計類型,第2行:“,街道地址,”

CREATE TABLE IF NOT EXISTS public.demographic_types (
    id bigint DEFAULT nextval('public.demographic_types_id_seq'::regclass) NOT NULL,
    demographic_type text NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL
);

Python代碼

def load_data(conn):
    """
    Load seeded data
    """
    db = os.environ['DATABASE_URL']
    dbname = db.replace("hsdp_pg","harbinger")
    try:
        with psycopg2.connect(dbname) as conn1:

            #migrate_db(conn, dbname, mirth_pw, harbinger_pw, psql_path, init_db)
            conn1.commit()
    except psycopg2.Error as exp1:
        print(exp1)
        print ('Error Code: %s. Error %s' % (exp1.pgcode, exp1.pgerror))


    print(conn1)
    path = os.path.dirname(os.path.realpath(__file__))    
    print (os.path.join(path,"database/data/*.csv"))
    for fle in sorted(glob.glob(os.path.join(path,"database/data/*.csv"))):
        print ('>>>Migrating data %s' % fle)
        table_name = os.path.basename(fle).replace('.csv', '')

        try:
            #silent_query(conn, sql, None)
            with conn1.cursor() as cur:
                #delete data first
                print('Deleting data from table  %s' % table_name)
                cur.execute('TRUNCATE %s CASCADE' % table_name)
                print('i am done and waiting')
                conn1.commit()


                with open(fle, 'r') as f:
                    #headers = ", ".join(table_column_mapping_data[table_name])
                    print("i am here ")
                    #cur.copy_from(f, table_name, sep=',')
                    #sql = "INSERT INTO %s (ID, demographic_type, updated_at) VALUES (%s,%s,%s)" % table_name
                    #record_insert = ('1', 'phone', '')
                    #cur.execute(sql, record_insert)
                    sql = "COPY %s from STDIN WITH CSV HEADER DELIMITER ','" % table_name
                    #print(sql)
                    cur.copy_expert(sql, f)
                    conn1.commit()
        except psycopg2.Error as exp2:
            print ('Error Code: %s. Error %s' % (exp2.pgcode, exp2.pgerror))

如果我理解正確,您想從 CSV 文件導入一些數據,但允許數據庫自動填充一些具有默認值的列(id 列的序列的 nextval 或 updated_at 列的 now() )。

為此,您必須告訴復制命令哪些列在 CSV 文件中,如下所示:

for fle in sorted(pathlib.path(path,"database/data/").glob("*.csv")):
    logging.info('>>>Migrating data %s', fle)
    table_name = fle.stem
    try:
        with conn1.cursor() as cur:
            logging.info('Deleting data from table %s', psycopg2.extensions.quote_ident(table_name))
            cur.execute('TRUNCATE %s CASCADE' % psycopg2.extensions.quote_ident(table_name, cur))
            logging.info('i am done and waiting')

            with open(fle, 'r') as f:
                cur.copy_from(
                    f,
                    table_name,
                    sep=',',
                    columns=[
                        'demographic_type',
                        'updated_at',
                        'street_address',
                        'city',
                        'state_or_province',
                        'postal_code',
                        'secondary_phone',
                        # more columns, but without id or created_at
                    ]
                )
        conn1.commit()
    except psycopg2.Error as exp2:
        print ('Error Code: %s. Error %s' % (exp2.pgcode, exp2.pgerror))

一點解釋 您面臨的主要問題來自對默認規范實際作用的誤解。 期望提供默認值意味着使用此值而不是 null會出現此問題。 情況並非如此,如果列列表中未提及列名稱,則在插入時指定默認值使用此值 因此給出以下內容:

create table use_default ( id       serial primary key
                         , column1  text
                         , column2  text default 'Undefined'
                         ) ;

insert into use_default(column1) values('abc');                         
-- gives the default to column2 as it is NOT mentioned in the insert 

select * from use_default; 
/* results in 
id  column1  column2
1   abc      Undefined
*/

insert into use_default(column1, column2)
  values ('def','given value')
       , ('ghi', null) ;
-- gives row def with column2 as 'given value' as it is specified
-- but row ghi has column2 as NULL. again as it was specified value

select * from use_default;
/*
id  column1 column2
1   abc     Undefined
2   def     given value
3   ghi     
*/ 

到目前為止,每個插入都生成了未指定的 id。 但僅僅因為它被指定為自動生成(由於串行定義在邏輯上最少),如果提供它,它仍然具有相同的處理。 注意有時不幸的是,NULL 是一個非常好的值。 所以:

 insert into use_default(id, column1) values (0,'Special id'); 
 Works just fine and gives the id as specified;

 select * from use_default where id = 0;
/*
id  column1    column2
0   Special id Undefined
*/


insert into use_default(id, column1) values(null, 'Special2');
/*
ERROR:  null value in column "id" violates not-null constraint
DETAIL:  Failing row contains (null, Special2, Undefined).
*/

現在您不會編寫試圖將 PK 設置為 null 的語句,但這本質上是 copy 命令正在執行的操作。 由於您沒有指定列,它嘗試使用 NULL 填充所有列而不是省略某些列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM