импортировать данные в PostgreSQL и экспортировать в CSV

avatar
ozn
9 августа 2021 в 06:30
918
2
1

Я пытаюсь выполнить импорт и экспорт данных csv с помощью postgresql (где база данных находится на удаленном хосте). Обычно я бы использовал команду psql для выполнения \copy <table> from <local path> ... и \copy <table> to <local path> ..., но мне нужно иметь возможность сделать это через Go, где у меня нет доступа к оболочке или системам, на которых не установлен psql.

Ожидается, что сами данные будут довольно легкими (возможно, < 2 МБ данных вместе), поэтому я стараюсь не реализовывать какие-либо структуры/схемы отслеживания столбцов в таблицах. При импорте в БД я хочу, чтобы библиотека/код выводила схему таблицы и помещала данные в таблицы.

Есть предложения, как это реализовать? Я не уверен, что любой из Go database/sql или pgx или pq позволяет это без возможности указывать столбцы. Есть какие-нибудь советы по этому поводу?

Изменить:

В итоге я использовал https://github.com/joho/sqltocsv для экспорта БД, что довольно просто, и мне не нужно определять какие-либо схемы/структуры.

У меня нет кода, но я попробовал gorm и понял, что мне нужно определить для него некоторую структуру/схему.

Источник
mkopriva
9 августа 2021 в 06:44
0

Можете ли вы поделиться с нами тем, что вы пробовали до сих пор, и с какими проблемами вы столкнулись? Кроме того, вы говорите, что пытаетесь реализовать структуры, но не можете указать столбцы, что подразумевает, что вы не знаете структуру, можете ли вы это пояснить? Вы знаете структуру данных или нет?

Aakash Goyal
9 августа 2021 в 07:09
0

Вы заглядывали в библиотеку горма?

Gustavo Kawamoto
9 августа 2021 в 08:46
1

Отвечает ли это на ваш вопрос? Массовая вставка из csv в postgres с использованием golang без использования цикла for

ozn
10 августа 2021 в 23:12
0

@mkopriva, правильно, что я не знаю структуру. Я просто знаю, что мне нужно будет экспортировать кучу данных и повторно импортировать их (в те же базы данных/таблицы). Очевидно, я мог бы использовать дамп БД, но данные там сложнее анализировать. Пока все, что у меня есть, в конечном итоге использует структуры и схемы, определенные для моих таблиц.

ozn
10 августа 2021 в 23:13
0

@Гауранга. У меня есть, и если я что-то не пропустил, мне нужно, чтобы в моем коде была определена какая-то схема. В идеале я хотел бы иметь возможность делать что-то простое, как команды psql.

ozn
10 августа 2021 в 23:13
0

@ГуставоКавамото. Это помогает, хотя код pgx не работает, возможно, дело в версии.

Ответы (2)

avatar
ozn
11 августа 2021 в 22:06
3

Я нашел способ сделать это с пакетом pgx (благодаря предложению @Gustavo Kawamoto). Вот мой импорт и экспорт:

package main

import (
    "fmt"
    "os"

    "github.com/jackc/pgx"
)

func main() {
    pgxConConfig := pgx.ConnConfig{
        Port:     5432,
        Host:     "remote_host",
        Database: "db_name",
        User:     "my_user",
        Password: "my_password",
    }

    conn, err := pgx.Connect(pgxConConfig)
    if err != nil {
        panic(err)
    }
    defer conn.Close()

    tables := []string{"table1", "table2", "table3",}

    import_dir := "/dir_to_import_from"
    export_dir := "/dir_to_export_to"
    
    for _, t := range tables {
        f, err := os.OpenFile(fmt.Sprintf("%s/table_%s.csv", import_dir, t), os.O_RDONLY, 0777)
        if err != nil {
            return
        }
        f.Close()

        err = importer(conn, f, t)
        if err != nil {
            break
        }

        fmt.Println("  Done with import and doing export")
        ef, err := os.OpenFile(fmt.Sprintf("%s/table_%s.csv", export_dir, t), os.O_CREATE|os.O_WRONLY, 0777)
        if err != nil {
            fmt.Println("error opening file:", err)
            return
        }
        ef.Close()

        err = exporter(conn, ef, t)
        if err != nil {
            break
        }
    }
}

func importer(conn *pgx.Conn, f *os.File, table string) error {
    res, err := conn.CopyFromReader(f, fmt.Sprintf("COPY %s FROM STDIN DELIMITER '|' CSV HEADER", table))
    if err != nil {
        return err
    }
    fmt.Println("==> import rows affected:", res.RowsAffected())

    return nil
}

func exporter(conn *pgx.Conn, f *os.File, table string) error {
    res, err := conn.CopyToWriter(f, fmt.Sprintf("COPY %s TO STDOUT DELIMITER '|' CSV HEADER", table))
    if err != nil {
        return fmt.Errorf("error exporting file: %+v", err)
    }
    fmt.Println("==> export rows affected:", res.RowsAffected())
    return nil
}
miek
23 января 2022 в 14:56
0

Это было действительно полезно, спасибо! Для тех, кто хочет специально экспортировать CSV в строку с go-pg, вы можете использовать db.CopyTo(buffer, query) с запросом типа COPY (select 'foo' as "a", 'bar' as "b") TO STDOUT WITH CSV HEADER DELIMITER ',';, и ваш буфер будет содержать результат экспорта CSV, готовый для использования в другом месте.

avatar
twiny
9 августа 2021 в 09:13
3

Оформить заказ на этот пакет: https://github.com/chop-dbhi/sql-importer

  1. Автоматическое создание таблицы
  2. Уникальность и обнаружение ненулевых значений.
  3. Поддержка файлов CSV, содержащих более 1600 столбцов (ограничение Postgres)
ozn
10 августа 2021 в 23:09
0

Я пытаюсь использовать это, но для этого требуется предоставить схему таблицы. Это верно? Хотелось бы, чтобы был пример схемы для указания. Я могу указать схему, которую использовал для создания таблицы, но у меня есть требование экспортировать/импортировать схему, которая не является жесткой.