วิธีคัดลอกจากไฟล์ CSV ไปยังตาราง PostgreSQL พร้อมส่วนหัวในไฟล์ CSV


93

ฉันต้องการคัดลอกไฟล์ CSV ไปยังตาราง Postgres มีคอลัมน์ประมาณ 100 คอลัมน์ในตารางนี้ดังนั้นฉันจึงไม่ต้องการเขียนซ้ำถ้าไม่ต้องทำ

ผมใช้\copy table from 'table.csv' delimiter ',' csv;คำสั่ง ERROR: relation "table" does not existแต่ไม่มีตารางที่สร้างฉันได้รับ ถ้าฉันเพิ่มตารางเปล่าฉันไม่พบข้อผิดพลาด แต่ไม่มีอะไรเกิดขึ้น ฉันลองคำสั่งนี้สองหรือสามครั้งและไม่มีผลลัพธ์หรือข้อความใด ๆ แต่ตารางไม่ได้รับการอัปเดตเมื่อฉันตรวจสอบผ่าน PGAdmin

มีวิธีการนำเข้าตารางที่มีส่วนหัวเหมือนที่ฉันพยายามทำหรือไม่


2
โต๊ะของคุณชื่อtable? สับสนมาก มีตารางอยู่หรือไม่หรือคุณต้องการสร้างตาม CSV (คุณทำไม่ได้)
wildplasser

1
ฉันตั้งชื่อมันอย่างอื่น แต่สำหรับตัวอย่างนี้ให้เรียกมันว่าตาราง ฉันลองทั้งที่ยังไม่มีมันอยู่ฉันก็พยายามทำ\copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;โดยไม่มีโชคเช่นกัน ตามหลักการแล้วตารางสามารถสร้างผ่าน CSV เพียงอย่างเดียวและใช้ส่วนหัวในไฟล์นั้น
Stanley Cup Phil

ที่เกี่ยวข้อง: stackoverflow.com/questions/2987433/…
G. Cito

2
โปรดแจ้งให้ทราบล่วงหน้าสำหรับทุกคนที่วางแผนจะเปลี่ยน csv ขนาดใหญ่ให้เป็นตาราง postgres - postgres ถูก จำกัด ไว้ที่ 1600 คอลัมน์ในตารางเดียว คุณไม่สามารถแยกตารางเป็นตารางขนาด 1600 คอลัมน์แล้วต่อเข้าด้วยกัน คุณต้องออกแบบฐานข้อมูลใหม่
Achekroud

หากหลามสามารถใช้ได้กับคุณคุณสามารถใช้d6tstack ดูแลการเปลี่ยนแปลงสคีมาด้วย
citynorman

คำตอบ:


135

สิ่งนี้ได้ผล แถวแรกมีชื่อคอลัมน์อยู่

COPY wheat FROM 'wheat_crop_data.csv' DELIMITER ';' CSV HEADER

5
ฉันคิดว่าปัญหาของคำสั่งนี้คือคุณต้องเป็น DB superuser \ copy ใช้งานได้เหมือนผู้ใช้ทั่วไปเช่นกัน
Exocom

29
COPYไม่ได้สร้างตารางหรือเพิ่มคอลัมน์เข้าไปมันจะเพิ่มแถวไปยังตารางที่มีอยู่ด้วยคอลัมน์ที่มีอยู่ สันนิษฐานว่าผู้ถามต้องการสร้างคอลัมน์ ~ 100 โดยอัตโนมัติและCOPYไม่มีฟังก์ชันนี้เนื่องจาก PG 9.3 เป็นอย่างน้อย
Daniel Vérité

2
@Exocom จับดี. เนื่องจากฉันไม่เคยเป็นผู้ดูแลระบบหรือผู้ใช้ขั้นสูงสำหรับฐานข้อมูลบนระบบ postgres ที่ฉันใช้ (pgadmin ทำให้ฉันเป็นเจ้าของฐานข้อมูลที่ฉันใช้และให้สิทธิ์ / บทบาทที่ จำกัด ) ฉันจึงต้องใช้ \ COPY ไชโย
G.Cito

2
@ Daniel ฉันเข้าใจว่าตารางของผู้ใช้มีอยู่แล้วและมีคอลัมน์ทั้งหมดที่ต้องการและต้องการเพียงแค่ADDข้อมูล
G.Cito

เตรียมพร้อมsyntax error at or near "HEADER" LINE 2: delimiter ',' CSV HEADERกับการเปลี่ยนสีแดง
มิ ธ ริล

24

ด้วยไลบรารี Python pandasคุณสามารถสร้างชื่อคอลัมน์และอนุมานชนิดข้อมูลจากไฟล์ csv ได้อย่างง่ายดาย

from sqlalchemy import create_engine
import pandas as pd

engine = create_engine('postgresql://user:pass@localhost/db_name')
df = pd.read_csv('/path/to/csv_file')
df.to_sql('pandas_db', engine)

พารามิเตอร์สามารถตั้งค่าที่จะเปลี่ยนหรือผนวกไปยังตารางที่มีอยู่เช่นif_exists df.to_sql('pandas_db', engine, if_exists='replace')งานนี้สำหรับชนิดแฟ้มการป้อนข้อมูลเพิ่มเติมรวมทั้งเอกสารที่นี่และที่นี่


1
ฉันพบว่า pd.DataFrame.from_csv ทำให้ฉันมีปัญหาน้อยลง แต่คำตอบนี้เป็นวิธีที่ง่ายที่สุดในการทำเช่นนี้ IMO
brock

ทรูมันนี่ผมไม่แน่ใจว่าทำไมผมพิมพ์แทนpd.read_excel pd.read_csvฉันอัปเดตคำตอบแล้ว
joelostblom

1
นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยมเมื่อคุณไม่ต้องการสร้างตารางไว้ล่วงหน้าซึ่งจะมีไฟล์ csv ขนาดใหญ่ โปรดทราบว่า postgres สามารถรับได้ 1600 คอลัมน์ในตารางเท่านั้น เห็นได้ชัดว่าเครื่องมือ DB อื่น ๆ จะอนุญาตมากขึ้น เห็นได้ชัดว่าการมีคอลัมน์จำนวนมากนี้เป็นรูปแบบ SQL ที่ไม่ดีแม้ว่าฉันทามตินี้จะยังไม่กรองไปถึงระบาดวิทยา
Achekroud

1
โดยค่าเริ่มต้นdf.to_sql()เป็นอย่างช้าเพื่อเพิ่มความเร็วในการนี้คุณสามารถใช้d6tstack ดูแลการเปลี่ยนแปลงสคีมาด้วย
citynorman

13

ทางเลือกโดยเทอร์มินัลโดยไม่ได้รับอนุญาต

เอกสาร PG ที่หมายเหตุ พูด

พา ธ จะถูกตีความโดยสัมพันธ์กับไดเร็กทอรีการทำงานของกระบวนการเซิร์ฟเวอร์ (โดยปกติคือไดเร็กทอรีข้อมูลของคลัสเตอร์) ไม่ใช่ไดเร็กทอรีการทำงานของไคลเอ็นต์

ดังนั้น gerally โดยใช้ psqlหรือไคลเอนต์ใด ๆ แม้ในเซิร์ฟเวอร์ภายในคุณมีปัญหา ... และหากคุณกำลังแสดงคำสั่ง COPY สำหรับผู้ใช้รายอื่นเช่น ที่ Github README ผู้อ่านจะมีปัญหา ...

วิธีเดียวที่จะแสดงเส้นทางสัมพันธ์กับลูกค้าสิทธิ์ใช้STDIN ,

เมื่อระบุ STDIN หรือ STDOUT ข้อมูลจะถูกส่งผ่านการเชื่อมต่อระหว่างไคลเอนต์และเซิร์ฟเวอร์

เท่าที่จำได้ที่นี่ :

psql -h remotehost -d remote_mydb -U myuser -c \
   "copy mytable (column1, column2) from STDIN with delimiter as ','" \
   < ./relative_path/file.csv

3

ฉันใช้ฟังก์ชันนี้มาระยะหนึ่งแล้วโดยไม่มีปัญหา คุณเพียงแค่ระบุคอลัมน์ตัวเลขที่มีอยู่ในไฟล์ csv และจะใช้ชื่อส่วนหัวจากแถวแรกและสร้างตารางให้คุณ:

create or replace function data.load_csv_file
    (
        target_table  text, -- name of the table that will be created
        csv_file_path text,
        col_count     integer
    )

    returns void

as $$

declare
    iter      integer; -- dummy integer to iterate columns with
    col       text; -- to keep column names in each iteration
    col_first text; -- first column name, e.g., top left corner on a csv file or spreadsheet

begin
    set schema 'data';

    create table temp_table ();

    -- add just enough number of columns
    for iter in 1..col_count
    loop
        execute format ('alter table temp_table add column col_%s text;', iter);
    end loop;

    -- copy the data from csv file
    execute format ('copy temp_table from %L with delimiter '','' quote ''"'' csv ', csv_file_path);

    iter := 1;
    col_first := (select col_1
                  from temp_table
                  limit 1);

    -- update the column names based on the first row which has the column names
    for col in execute format ('select unnest(string_to_array(trim(temp_table::text, ''()''), '','')) from temp_table where col_1 = %L', col_first)
    loop
        execute format ('alter table temp_table rename column col_%s to %s', iter, col);
        iter := iter + 1;
    end loop;

    -- delete the columns row // using quote_ident or %I does not work here!?
    execute format ('delete from temp_table where %s = %L', col_first, col_first);

    -- change the temp table name to the name given as parameter, if not blank
    if length (target_table) > 0 then
        execute format ('alter table temp_table rename to %I', target_table);
    end if;
end;

$$ language plpgsql;

อย่าลืมเปลี่ยนset schema 'data';เป็นอะไรก็ได้สำหรับคุณ
mehmet

0

คุณสามารถใช้d6tstackซึ่งสร้างตารางให้คุณและเร็วกว่า pd.to_sql ()เนื่องจากใช้คำสั่งการนำเข้า DB ดั้งเดิม รองรับ Postgres เช่นเดียวกับ MYSQL และ MS SQL

import pandas as pd
df = pd.read_csv('table.csv')
uri_psql = 'postgresql+psycopg2://usr:pwd@localhost/db'
d6tstack.utils.pd_to_psql(df, uri_psql, 'table')

นอกจากนี้ยังมีประโยชน์สำหรับการนำเข้า CSV หลายรายการการแก้ปัญหาการเปลี่ยนแปลงสคีมาข้อมูลและ / หรือการประมวลผลล่วงหน้าด้วยแพนด้า (เช่นวันที่) ก่อนที่จะเขียนลงฐานข้อมูลดูเพิ่มเติมในสมุดบันทึกตัวอย่าง

d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), 
    apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.