df.to_sql('TableNameHere', engine, if_exists='append', chunksize=900, index=False)
Estoy tratando de agregar un DataFrame grande a una tabla SQL. Algunas de las filas del DataFrame son duplicados de las de la tabla SQL, otras no. Pero to_sql()
deja de ejecutarse por completo si se detecta incluso un duplicado.
Tendría sentido que to_sql(if_exists='append')
simplemente advierta al usuario qué filas tienen claves duplicadas y simplemente continúe agregando las nuevas filas, no deje de ejecutarse por completo. Para grandes conjuntos de datos, es probable que tenga duplicados, pero querrá ignorarlos.
¿Quizás agregar un argumento para ignorar los duplicados y seguir ejecutando? ¿Quizás una opción adicional if_exists
como 'append_skipdupes'
?
pd.show_versions()
compromiso: ninguno
pitón: 3.6.0.final.0
bits de Python: 64
SO: Windows
Lanzamiento del sistema operativo: 10
máquina: AMD64
Procesador: Intel64 Familia 6 Modelo 60 Paso 3, GenuineIntel
orden de bytes: pequeño
LC_ALL: Ninguno
IDIOMA: Ninguno
LOCAL: inglés_Estados Unidos.1252
pandas: 0.19.2
nariz: Ninguno
pipa: 9.0.1
herramientas de configuración: 28.8.0
Citón: Ninguno
número: 1.12.0
espía: Ninguno
modelos estadísticos: Ninguno
matriz: ninguno
Python: 5.3.0
esfinge: Ninguno
Paty: Ninguno
dateutil: 2.6.0
Pytz: 2016.10
bloque: Ninguno
cuello de botella: Ninguno
tablas: ninguna
exprnumero: Ninguno
matplotlib: Ninguno
openpyxl: Ninguno
xlrd: Ninguno
xlwt: Ninguno
xlsxwriter: Ninguno
lxml: Ninguno
bs4: Ninguno
html5lib: 0.999999999
httplib2: Ninguno
apiciente: Ninguno
sqlalchemy: 1.1.9
pymysql: Ninguno
psycopg2: Ninguno
jinja2: 2.9.5
Boto: Ninguno
pandas_datareader: Ninguno
Esto también debería ser compatible con el modo "en actualización duplicada".
@rosstripi Creo que la idea de tener esto ciertamente sería aceptada, pero AFAIK el principal cuello de botella es una implementación para esto usando sql/sqlalchemy de una manera agnóstica. ¡Alguna exploración de cómo se podría hacer esto es ciertamente bienvenida!
Hola, encontraste alguna solución para esto? Por favor hagamelo saber
¿Alguna actualización sobre esta implementación?
Ahora estoy enfrentando este problema con PostgreSQL y SQLAlchemy y me encantaría tener eso "en actualización duplicada".
gracias por el trabajo
Una solución sería eliminar el índice único en la base de datos:
sqlquery="ALTER 'TABLE DATABASE'.'TABLE' DROP INDEX 'idx_name'"
después
df.to_sql('TableNameHere', engine, if_exists='append', chunksize=900, index=False)
se puede ejecutar
Simplemente deje que su servidor MySQL agregue el índice nuevamente y elimine los duplicados.
sqlquery="ALTER IGNORE TABLE 'DATABASE'.'TABLE' ADD UNIQUE INDEX 'idx_name' ('column_name1' ASC, 'column_name2' ASC, 'column_name3' '[ASC | DESC]')"
Dependiendo de su aplicación específica, esto puede ser útil.
De todos modos, la opción if_exists
como append_skipdupes
sería mucho mejor.
append_skipdupes
sería la manera perfecta de manejar esto.
sí, append_skipdupes +1
Acordé que sería bueno poder lidiar con esto con opciones en df.to_sql()
.
Aquí está la solución que uso en sqlite:
CREATE TABLE IF NOT EXISTS my_table_name (
some_kind_of_id INT PRIMARY KEY ON CONFLICT IGNORE,
...
Luego, cuando inserto duplicados, se ignoran silenciosamente y los no duplicados se procesan correctamente. En mi caso, los datos son (es decir , deberían ser ) estáticos, por lo que no necesito actualizarlos. Es solo que la forma de la fuente de datos es tal que obtendré duplicados que se pueden ignorar.
otra solución alternativa con MariaDb y MySql:
df.to_csv("test.csv")
entonces usa:
LOAD DATA INFILE 'test.csv' IGNORE INTO TABLE mytable
o
LOAD DATA INFILE 'test.csv' REPLACE INTO TABLE mytable
.
LOAD DATA es mucho más rápido que INSERT.
código completo:
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()))
Creo que esto se está abordando en #29636 con el argumento upsert_ignore
, que aborda #14553.
append_skipdupes +1
+1 por append_skipdupes
De acuerdo, se debe agregar 'append_skipdupes'.
Sí, por favor. Se debe agregar 'append_skipdupes' y no solo para la columna Clave principal. Si hay duplicados entre otras columnas únicas, también debe omitir la adición de esas nuevas filas duplicadas.
+1 por append_skipdupes
append_skipdupes +1
append_skipdupes +1
+1 por append_skipdupes
Mientras tanto puedes usar este https://pypi.org/project/pangres/
Comentario más útil
Esto también debería ser compatible con el modo "en actualización duplicada".