Python / SQL: reemplazar las cadenas vacías de un DataFrame por un valor "Null" para insertar los datos en una base de datos

Nov 29 2020

Digamos que tengo este marco de datos:

REFERENCE = ["GZF882348G", "SFGUZBJLNJU", "FTLNGZ242112", "DFBHGVGHG543"]
IBAN = ["FR7343563", "FR4832545", "FR9858331", "FR2001045"]
DEBIT = [26, '', 856, '']
CREDIT = ['', 324, '', 876]
MONTANT = [641, 33, '', 968]

df = pd.DataFrame({'Référence' : REFERENCE, 'IBAN' : IBAN, 'Débit' : DEBIT, 'Crédit' : CREDIT, 'Montant' : MONTANT})

Tengo un problema de formato para insertar este tipo de datos en mi base de datos. Las columnas "Débit", "Crédit", "Montant" se definen para obtener flotantes como datos. Sin embargo, los datos de estas columnas no son solo números enteros, también tengo cadenas vacías y ese es mi problema. Sé que tengo que escribir una condición que reemplace una cadena vacía por un valor "Nulo" en el formato SQL, sin embargo, no sé cómo hacerlo en Python o SQL. Estoy descubriendo / aprendiendo el entorno SQL.

Aquí está mi código:

import pandas as pd
import pyodbc 

server = '...'
database = '...'
username = '...' 
password = '...'
driver = '...'

connection = pyodbc.connect('DRIVER='+driver+';SERVER='+server+';PORT=1433;DATABASE='+database+';UID='+username+';PWD='+password)
cursor = connection.cursor()

for i, row in df.iterrows():


    sql_exe = "INSERT INTO dbo.tbl_data_xml (Réference,IBAN,Débit,Crédit,Montant) VALUES (?,?,?,?,?)"
    cursor.execute(sql_exe, tuple(row))
    
    connection.commit()

Cualquiera puede ayudarme por favor.

Gracias

Respuestas

1 Parfait Nov 30 2020 at 02:13

Parece que está mezclando tipos en el marco de datos de Pandas donde la cadena,, ''se combina con un entero en la misma columna, como lo demuestran todos los objecttipos. En las bases de datos relacionales no se pueden mezclar tipos de datos. Y la conversión ''a cadena 'NULL'no resolverá su problema. En SQL,NULL <> 'NULL'

df.dtypes

# Référence    object
# IBAN         object
# Débit        object
# Crédit       object
# Montant      object
# dtype: object

Por lo tanto, convierta las columnas a numéricas con pd.to_numericdonde la cadena vacía,, se ''convierte a lo NaNque esta entidad debería traducirse a la NULLentidad de SQL .

df[['Débit', 'Crédit', 'Montant']] = df[['Débit', 'Crédit', 'Montant']].apply(pd.to_numeric)

df.dtypes
# Référence     object
# IBAN          object
# Débit        float64
# Crédit       float64
# Montant      float64
# dtype: object

df
#       Référence       IBAN  Débit  Crédit  Montant
# 0    GZF882348G  FR7343563   26.0     NaN    641.0
# 1   SFGUZBJLNJU  FR4832545    NaN   324.0     33.0
# 2  FTLNGZ242112  FR9858331  856.0     NaN      NaN
# 3  DFBHGVGHG543  FR2001045    NaN   876.0    968.0

Luego ejecute su consulta. De hecho, evite el forciclo más lento con iterrowsy considere df.to_numpy+ cursor.executemany.

# PREPARED STATEMENT
sql_exe = "INSERT INTO dbo.tbl_data_xml (Réference,IBAN,Débit,Crédit,Montant) VALUES (?,?,?,?,?)"

# CONVERT DATA TO LIST OF NUMPY ARRAYS
sql_data = df.where(pd.notnull(df), None).to_numpy().replace(.tolist()

# EXECUTE ACTION QUERY
cursor.executemany(sql_exe, sql_data)
connection.commit()
1 BarbarosÖzhan Nov 29 2020 at 21:32

Puedes usar Pandas.DataFrame.to_sqlcomo

df.to_sql('dbo.tbl_data_xml', con=connection, if_exists='append', index=False )

donde appendopción significa insertar nuevos valores en la tabla, si la versión de pandas es 0.15+

DaniMesejo Nov 29 2020 at 21:30

Podrías hacerlo:

df.loc[df['Débit'].eq(''), 'Débit'] = 'NULL'
df.loc[df['Crédit'].eq(''), 'Crédit'] = 'NULL'
df.loc[df['Montant'].eq(''), 'Montant'] = 'NULL'

print(df)

Salida

      Référence       IBAN Débit Crédit Montant
0    GZF882348G  FR7343563    26   NULL     641
1   SFGUZBJLNJU  FR4832545  NULL    324      33
2  FTLNGZ242112  FR9858331   856   NULL    NULL
3  DFBHGVGHG543  FR2001045  NULL    876     968

O simplemente,

df[df[['Débit', 'Crédit', 'Montant']].eq('')] = "NULL"
print(df)

Salida

      Référence       IBAN Débit Crédit Montant
0    GZF882348G  FR7343563    26   NULL     641
1   SFGUZBJLNJU  FR4832545  NULL    324      33
2  FTLNGZ242112  FR9858331   856   NULL    NULL
3  DFBHGVGHG543  FR2001045  NULL    876     968
wwnde Nov 29 2020 at 21:35

Convierta a numericlas columnas respectivas yfillna(NULL)

df[['Débit', 'Crédit', 'Montant']]=df.iloc[:,2:].apply(lambda x: pd.to_numeric(x).fillna('NULL'))



     Référence       IBAN Débit Crédit Montant
0    GZF882348G  FR7343563    26   NULL     641
1   SFGUZBJLNJU  FR4832545  NULL    324      33
2  FTLNGZ242112  FR9858331   856   NULL    NULL
3  DFBHGVGHG543  FR2001045  NULL    876     968