[PYTHON] Insérer à partir de pd.DataFrame avec psycopg2

J'ai essayé d'insérer en me référant à l'article ici, mais j'ai trébuché, donc je vais l'écrire. C'est presque la même chose, mais il y avait deux problèmes avec l'insertion de chaînes de caractères. Erreur de codage lors de l'insertion d'une chaîne de caractères japonais et erreur de codage d'une chaîne de caractères comprenant une barre oblique inverse.

la mise en oeuvre

from io import StringIO
from typing import List

import pandas as pd
import psycopg2

class Client:
    def __init__(self, dsn: str) -> None:
        """
        Arguments:
            dsn(str): 'postgresql://{username}:{password}@{hostname}:{port}/{dbname}'
        """
        self._cur = None
        self._conn = psycopg2.connect(dsn)
        self._conn.set_client_encoding('UTF8')
        self._cur = self._conn.cursor()

    def __del__(self) -> None:
        if self._cur is not None:
            self._cur.close()

        self._conn.close()

    def insert(self, table: str, values: pd.DataFrame) -> None:
        buf = StringIO()
        df.to_csv(buf, sep='\t', na_rep='\\N', index=False, header=False)
        buf.seek(0)
        columns = df.columns.values.tolist()
        self._cur.copy_from(buf, table, columns=columns)
        self._conn.commit()

Cela ne s'est pas produit cette fois, mais il semble que cela puisse aussi être une erreur lors du traitement des types entiers NULLABLE dans pd.DataFrame. Voir aussi: https://qiita.com/hoto17296/items/b6c90db4b9bcdb7b6d78

import os


df = get_dataframe()  #Résolu avec `set_client_encoding ('UTF8')` Référence: https://www.psycopg.org/docs/connection.html#connection.set_client_encoding Problème de backslash J'ai implémenté cela de l'extérieur, mais cela ressemble à ceci: Je l'ai évité. Supposons que la colonne «a» soit une chaîne. Récupérez le bloc de données par n'importe quelle méthode.
df.a = df.a.str.replace('\\', '\\\\')

client = Client(os.environ.get('POSTGRES_DSN')
client.insert(table, df)

Autres implémentations

Dans ce qui précède, nous avons utilisé copy_from, mais lorsque vous utilisez copy_expert, nous pouvons écrire comme suit.

cur.copy_expert(
    f"""
        COPY {table}(
            {','.join(columns)}
        )
        FROM STDIN
        WITH
            DELIMITER AS ' '
            NULL AS '\\N'
        ENCODING 'utf8'
    """,
    buf,
)

Nous n'avons pas besoin de set_client_encoding ('UTF8') car nous spécifions l'encodage dans la requête.

Référence: https://www.psycopg.org/docs/cursor.html#cursor.copy_expert

Recommended Posts

Insérer à partir de pd.DataFrame avec psycopg2
Bulk Insert Pandas DataFrame avec psycopg2
Générez une instruction d'insertion à partir de CSV avec Python.
Avec skype, notifiez avec skype de python!
Appeler C depuis Python avec DragonFFI
Installez Python à partir des sources avec Ansible
Obtenir une colonne de DataFrame avec DataFrame
À propos des transactions lors de l'utilisation de PostgreSQL avec Psycopg2
Libre de codage en dur des fonctions avec SymPy
Exécutez Aprili depuis Python sur Orange
Exploitez Maya avec OSC depuis vvvv
Appelez python de nim avec Nimpy
Utiliser PostgreSQL avec Lambda (Python + psycopg2)
Charger fbx depuis python avec cinema4d