Làm cách nào để sao chép từ tệp CSV sang bảng PostgreSQL với tiêu đề trong tệp CSV?


93

Tôi muốn sao chép tệp CSV vào bảng Postgres. Có khoảng 100 cột trong bảng này, vì vậy tôi không muốn viết lại chúng nếu tôi không cần thiết.

Tôi đang sử dụng \copy table from 'table.csv' delimiter ',' csv;lệnh nhưng không có bảng được tạo, tôi nhận được ERROR: relation "table" does not exist. Nếu tôi thêm một bảng trống, tôi không gặp lỗi, nhưng không có gì xảy ra. Tôi đã thử lệnh này hai hoặc ba lần và không có đầu ra hoặc thông báo, nhưng bảng không được cập nhật khi tôi kiểm tra nó qua PGAdmin.

Có cách nào để nhập một bảng với các tiêu đề được bao gồm như tôi đang cố gắng làm không?


2
Bảng của bạn được đặt tên table? Rất bối rối. Bảng có tồn tại không hay bạn muốn tạo nó dựa trên CSV? (bạn có thể không)
wildplasser

1
tốt, tôi đã đặt tên cho nó một cái gì đó khác, nhưng trong ví dụ này, hãy gọi nó là bảng. Tôi đã cố gắng và không có nó hiện tại, tôi cũng cố gắng làm \copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;mà không có may mắn. Lý tưởng nhất là bảng có thể được tạo thông qua CSV một mình và sử dụng các tiêu đề trong tệp đó.
Stanley Cup Phil


2
Chỉ cần lưu ý cho bất kỳ ai có kế hoạch biến một csv lớn thành một bảng postgres - postgres được giới hạn ở 1600 cột trong một bảng. Bạn không thể phân chia các bảng thành những bảng có kích thước 1600 cột rồi nối chúng lại với nhau. Bạn cần thiết kế lại db.
Achekroud

Nếu bạn có python, bạn có thể sử dụng d6tstack . Nó cũng xử lý các thay đổi giản đồ.
citynorman 14/10/18

Câu trả lời:


132

Điều này đã hiệu quả. Hàng đầu tiên có tên cột trong đó.

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

5
Tôi nghĩ vấn đề với lệnh này là bạn phải là siêu người dùng DB. \ copy cũng hoạt động như người dùng bình thường
Exocom

28
COPYkhông tạo bảng hoặc thêm cột vào bảng, nó thêm hàng vào bảng hiện có với các cột hiện có của nó. Có lẽ người hỏi muốn tự động tạo ~ 100 cột và COPYkhông có chức năng này, ít nhất là PG 9.3.
Daniel Vérité

2
@Exocom bắt tốt. Vì tôi chưa bao giờ là quản trị viên hoặc người dùng cấp cao cho DB trên các hệ thống postgres mà tôi sử dụng (pgadmin khiến tôi trở thành chủ sở hữu của cơ sở dữ liệu tôi sử dụng và cấp cho tôi các đặc quyền / vai trò hạn chế) nên tôi đã sử dụng `\ COPY '. Chúc mừng
G. Cito

2
@Daniel Tôi hiểu bảng của người dùng đã tồn tại và có tất cả các cột họ cần và họ muốnADD dữ liệu đơn giản .
G. Cito

Đã nhận được syntax error at or near "HEADER" LINE 2: delimiter ',' CSV HEADERdịch chuyển đỏ.
Mithril

24

Với thư viện Python pandas, bạn có thể dễ dàng tạo tên cột và suy ra kiểu dữ liệu từ tệp 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)

Các if_existstham số có thể được thiết lập để thay thế hoặc append vào một bảng hiện có, ví dụ df.to_sql('pandas_db', engine, if_exists='replace'). Điều này cũng hoạt động cho các loại tệp đầu vào bổ sung, tài liệu ở đâyở đây .


1
Tôi thấy rằng pd.DataFrame.from_csv mang lại cho tôi ít rắc rối hơn, nhưng câu trả lời này cho đến nay là cách dễ nhất để làm điều này, IMO.
brock

Đúng, tôi không chắc tại sao tôi lại nhập pd.read_excel, thay vì pd.read_csv. Tôi đã cập nhật câu trả lời.
joelostblom

1
đây là một giải pháp tuyệt vời khi bạn không muốn tạo trước bảng sẽ chứa một csv lớn. Tuy nhiên, chỉ cần lưu ý - các postgres chỉ có thể chiếm 1600 cột trong một bảng. Rõ ràng các công cụ DB khác sẽ cho phép nhiều hơn thế. Có nhiều cột như vậy rõ ràng là dạng SQL kém, mặc dù sự đồng thuận này vẫn chưa được lọc qua dịch tễ học.
Achekroud

1
Theo mặc định df.to_sql()là RẤT CHẬM, để tăng tốc độ này, bạn có thể sử dụng d6tstack . Nó cũng xử lý các thay đổi giản đồ.
citynorman 14/10/18

13

Thay thế bằng thiết bị đầu cuối không có sự cho phép

Các tài liệu pg tại GHI CHÚ nói

Đường dẫn sẽ được diễn giải liên quan đến thư mục làm việc của tiến trình máy chủ (thường là thư mục dữ liệu của cụm), không phải thư mục làm việc của máy khách.

Vì vậy, về mặt địa lý, sử dụng psqlhoặc bất kỳ máy khách nào, ngay cả trong một máy chủ cục bộ, bạn cũng gặp vấn đề ... Và, nếu bạn đang thể hiện lệnh COPY cho người dùng khác, chẳng hạn. tại Github README, người đọc sẽ gặp vấn đề ...

Cách duy nhất để thể hiện đường dẫn tương đối với quyền của máy khách là sử dụng STDIN ,

Khi STDIN hoặc STDOUT được chỉ định, dữ liệu được truyền qua kết nối giữa máy khách và máy chủ.

như đã nhớ ở đây :

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

3

Tôi đã sử dụng chức năng này trong một thời gian mà không gặp vấn đề gì. Bạn chỉ cần cung cấp số cột có trong tệp csv và nó sẽ lấy tên tiêu đề từ hàng đầu tiên và tạo bảng cho bạn:

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;

đừng quên thay đổi set schema 'data';thành bất cứ điều gì phù hợp với bạn
mehmet

0

Bạn có thể sử dụng d6tstack để tạo bảng cho bạn và nhanh hơn pd.to_sql () vì nó sử dụng các lệnh nhập DB gốc. Nó hỗ trợ Postgres cũng như MYSQL và 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')

Nó cũng hữu ích để nhập nhiều CSV, giải quyết các thay đổi lược đồ dữ liệu và / hoặc xử lý trước với gấu trúc (ví dụ: cho ngày tháng) trước khi ghi vào db, xem thêm trong sổ tay ví dụ

d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), 
    apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.