sql >> Databáze >  >> RDS >> PostgreSQL

Kopírování CSV do Postgres s polem vlastního typu pomocí JDBC

Viz https://git.mikael.io/mikaelhg/pg -object-csv-copy-poc/ pro projekt s testem JUnit, který dělá to, co chcete.

V zásadě chcete mít možnost používat čárky pro dvě věci:k oddělení položek pole a k oddělení polí typu, ale NECHCETE, aby analýza CSV interpretovala čárky jako vymezovače polí.

Takže

  1. chcete sdělit analyzátoru CSV, aby považoval celý řádek za jeden řetězec, jedno pole, což můžete provést tak, že jej uzavřete do jednoduchých uvozovek a sdělíte to analyzátoru CSV, a
  2. chcete, aby analyzátor polí PG považoval každou instanci typu položky pole za uzavřenou do dvojitých uvozovek.

Kód:

copyManager.copyIn("COPY my_table (addresses) FROM STDIN WITH CSV QUOTE ''''", reader);

Příklad DML 1:

COPY my_table (addresses) FROM STDIN WITH CSV QUOTE ''''

CSV příklad 1:

'{"(10.0.0.1,1)","(10.0.0.2,2)"}'
'{"(10.10.10.1,80)","(10.10.10.2,443)"}'
'{"(10.10.10.3,8080)","(10.10.10.4,4040)"}'

Příklad DML 2, escapování dvojitých uvozovek:

COPY my_table (addresses) FROM STDIN WITH CSV

CSV příklad 2, escapování do dvojitých uvozovek:

"{""(10.0.0.1,1)"",""(10.0.0.2,2)""}"
"{""(10.10.10.1,80)"",""(10.10.10.2,443)""}"
"{""(10.10.10.3,8080)"",""(10.10.10.4,4040)""}"

Plná testovací třída JUnit:

package io.mikael.poc;

import com.google.common.io.CharStreams;
import org.junit.*;
import org.postgresql.PGConnection;
import org.postgresql.copy.CopyManager;
import org.testcontainers.containers.PostgreSQLContainer;

import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;

import static java.nio.charset.StandardCharsets.UTF_8;

public class CopyTest {

    private Reader reader;

    private Connection connection;

    private CopyManager copyManager;

    private static final String CREATE_TYPE = "CREATE TYPE address AS (ip inet, port int)";

    private static final String CREATE_TABLE = "CREATE TABLE my_table (addresses  address[] NULL)";

    private String loadCsvFromFile(final String fileName) throws IOException {
        try (InputStream is = getClass().getResourceAsStream(fileName)) {
            return CharStreams.toString(new InputStreamReader(is, UTF_8));
        }
    }

    @ClassRule
    public static PostgreSQLContainer db = new PostgreSQLContainer("postgres:10-alpine");

    @BeforeClass
    public static void beforeClass() throws Exception {
        Class.forName("org.postgresql.Driver");
    }

    @Before
    public void before() throws Exception {
        String input = loadCsvFromFile("/data_01.csv");
        reader = new StringReader(input);

        connection = DriverManager.getConnection(db.getJdbcUrl(), db.getUsername(), db.getPassword());
        copyManager = connection.unwrap(PGConnection.class).getCopyAPI();

        connection.setAutoCommit(false);
        connection.beginRequest();

        connection.prepareCall(CREATE_TYPE).execute();
        connection.prepareCall(CREATE_TABLE).execute();
    }

    @After
    public void after() throws Exception {
        connection.rollback();
    }

    @Test
    public void copyTest01() throws Exception {
        copyManager.copyIn("COPY my_table (addresses) FROM STDIN WITH CSV QUOTE ''''", reader);

        final StringWriter writer = new StringWriter();
        copyManager.copyOut("COPY my_table TO STDOUT WITH CSV", writer);
        System.out.printf("roundtrip:%n%s%n", writer.toString());

        final ResultSet rs = connection.prepareStatement(
                "SELECT array_to_json(array_agg(t)) FROM (SELECT addresses FROM my_table) t")
                .executeQuery();
        rs.next();
        System.out.printf("json:%n%s%n", rs.getString(1));
    }

}

Testovací výstup:

roundtrip:
"{""(10.0.0.1,1)"",""(10.0.0.2,2)""}"
"{""(10.10.10.1,80)"",""(10.10.10.2,443)""}"
"{""(10.10.10.3,8080)"",""(10.10.10.4,4040)""}"

json:
[{"addresses":[{"ip":"10.0.0.1","port":1},{"ip":"10.0.0.2","port":2}]},{"addresses":[{"ip":"10.10.10.1","port":80},{"ip":"10.10.10.2","port":443}]},{"addresses":[{"ip":"10.10.10.3","port":8080},{"ip":"10.10.10.4","port":4040}]}]


  1. Navrhovaný způsob, jak spustit více příkazů SQL v pythonu?

  2. Volání uložené funkce (která vrací pole uživatelem definovaného typu) v oracle přes odkaz na databázi

  3. Volejte uloženou proceduru Oracle z Java App pomocí hibernace a fondu připojení c3p0

  4. Node.js a Microsoft SQL Server