Pandas: Bei Verwendung von to_sql() fortfahren, wenn doppelte Primärschlüssel erkannt werden?

Erstellt am 13. Apr. 2017  ·  19Kommentare  ·  Quelle: pandas-dev/pandas

Codebeispiel, wenn möglich ein kopierfähiges Beispiel

df.to_sql('TableNameHere', engine, if_exists='append', chunksize=900, index=False)

Problembeschreibung

Ich versuche, einen großen DataFrame an eine SQL-Tabelle anzuhängen. Einige der Zeilen im DataFrame sind Duplikate der Zeilen in der SQL-Tabelle, andere nicht. Aber to_sql() stoppt die Ausführung vollständig, wenn auch nur ein Duplikat erkannt wird.

Es wäre für to_sql(if_exists='append') sinnvoll, den Benutzer lediglich zu warnen, welche Zeilen doppelte Schlüssel enthalten, und einfach die neuen Zeilen hinzuzufügen und die Ausführung nicht vollständig zu stoppen. Bei großen Datasets werden Sie wahrscheinlich Duplikate haben, die Sie aber ignorieren möchten.

Vielleicht fügen Sie ein Argument hinzu, um Duplikate zu ignorieren und die Ausführung fortzusetzen? Vielleicht eine zusätzliche if_exists Option wie 'append_skipdupes' ?

Ausgabe von pd.show_versions()

INSTALLIERTE VERSIONEN

verpflichten: Keine
Python: 3.6.0.final.0
Python-Bits: 64
Betriebssystem: Windows
OS-Release: 10
Maschine: AMD64
Prozessor: Intel64 Family 6 Model 60 Stepping 3, GenuineIntel
Bytereihenfolge: wenig
LC_ALL: Keine
LANG: Nein
LOCALE: Englisch_Vereinigte Staaten.1252

Pandas: 0.19.2
Nase: Keine
Pip: 9.0.1
Setuptools: 28.8.0
Cyton: Nein
numpy: 1.12.0
scipy: Nein
Statistikmodelle: Keine
xarray: Nein
IPython: 5.3.0
Sphinx: Nein
patsy: Nein
dateutil: 2.6.0
pytz: 2016.10
blosc: Nein
Engpass: Keine
Tabellen: Keine
numexpr: Keine
matplotlib: Keine
openpyxl: Keine
xlrd: Keine
xlwt: Keine
xlsxwriter: Keine
lxml: Keine
bs4: Keine
html5lib: 0.999999999
httplib2: Keine
Antragsteller: Nein
SQL-Chemie: 1.1.9
pymysql: Keine
psycopg2: Keine
Jinja2: 2.9.5
boto: Nein
pandas_datareader: Keine

Enhancement IO SQL

Hilfreichster Kommentar

Dies sollte auch den Modus „bei doppelter Aktualisierung“ unterstützen.

Alle 19 Kommentare

Dies sollte auch den Modus „bei doppelter Aktualisierung“ unterstützen.

@rosstripi Ich denke, die Idee, dies zu haben, würde sicherlich akzeptiert werden, aber AFAIK ist der Hauptengpass eine Implementierung dafür, die sql/sqlalchemy auf geschmacksunabhängige Weise verwendet. Eine Erkundung, wie dies bewerkstelligt werden könnte, ist sicherlich willkommen!

Hallo, hast du einen Workaround dafür gefunden? Lass es mich wissen, bitte

Irgendwelche Updates zu dieser Implementierung?

Ich stehe jetzt vor diesem Problem mit PostgreSQL und SQLAlchemy und würde das gerne "bei doppeltem Update" haben.

Danke für die Arbeit

Eine Problemumgehung wäre, den eindeutigen Index in der Datenbank zu entfernen:

sqlquery="ALTER 'TABLE DATABASE'.'TABLE' DROP INDEX 'idx_name'"
nachher
df.to_sql('TableNameHere', engine, if_exists='append', chunksize=900, index=False)
ausgeführt werden kann.

Lassen Sie einfach Ihren MySQL-Server den Index erneut hinzufügen und die Duplikate löschen.
sqlquery="ALTER IGNORE TABLE 'DATABASE'.'TABLE' ADD UNIQUE INDEX 'idx_name' ('column_name1' ASC, 'column_name2' ASC, 'column_name3' '[ASC | DESC]')"

Abhängig von Ihrer spezifischen Anwendung kann dies hilfreich sein.
Wie auch immer, if_exists Option wie append_skipdupes wäre viel besser.

append_skipdupes wäre der perfekte Weg, damit umzugehen.

Ja, append_skipdupes +1

Einverstanden, dass es gut wäre, dies mit Optionen in df.to_sql() behandeln zu können.

Hier ist die Problemumgehung, die ich in SQLite verwende:

CREATE TABLE IF NOT EXISTS my_table_name (
    some_kind_of_id INT PRIMARY KEY ON CONFLICT IGNORE,
    ...

Wenn ich dann Duplikate einfüge, werden sie stillschweigend ignoriert und die Nicht-Duplikate werden korrekt verarbeitet. In meinem Fall sind (dh sollten ) die Daten statisch, sodass ich sie nicht aktualisieren muss. Es ist nur so, dass die Form des Datenfeeds so ist, dass ich Duplikate bekomme, die ignoriert werden können.

eine andere Problemumgehung mit MariaDb und MySql :
df.to_csv("test.csv")
dann benutze :
LOAD DATA INFILE 'test.csv' IGNORE INTO TABLE mytable oder
LOAD DATA INFILE 'test.csv' REPLACE INTO TABLE mytable .

LOAD DATA ist sehr viel schneller als INSERT.

vollständiger Code:

csv_path = str(Path(application_path) / "tmp" / "tmp.csv").replace("\\", "\\\\")
df.to_csv(csv_path, index=False, sep='\t', quotechar="'", na_rep=r'\N')
rq = """LOAD DATA LOCAL INFILE '{file_path}' REPLACE INTO TABLE {db}.{db_table}
        LINES TERMINATED BY '\\r\\n'
        IGNORE 1 LINES
         ({col});
        """.format(db=db,
                   file_path=csv_path,
                   db_table=table_name,
                   col=",".join(df.columns.tolist()))

Ich glaube, dies wird in #29636 mit dem Argument upsert_ignore angesprochen, das #14553 adressiert.

append_skipdupes +1

+1 für append_skipdupes

Stimmen Sie zu, dass 'append_skipdupes' hinzugefügt werden sollte.

Ja bitte. 'append_skipdupes' sollte hinzugefügt werden und nicht nur für die Primärschlüsselspalte. Wenn unter anderen eindeutigen Spalten Duplikate vorhanden sind, sollte das Anhängen dieser neuen doppelten Zeilen ebenfalls übersprungen werden.

+1 für append_skipdupes

append_skipdupes +1

append_skipdupes +1

+1 für append_skipdupes

In der Zwischenzeit können Sie dies https://pypi.org/project/pangres/ verwenden

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen