Python / SQL: substituindo as strings vazias de um DataFrame por um valor “Null” para inserir os dados em um banco de dados

Nov 29 2020

Digamos que eu tenha este dataframe:

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})

Estou com um problema de formato para inserir este tipo de dados em meu banco de dados. As colunas "Débit", "Crédit", "Montant" são definidas para obter flutuações como dados. No entanto, os dados dessas colunas não são apenas inteiros, também tenho strings vazias e esse é o meu problema. Eu sei que tenho que escrever uma condição que substitua uma string vazia por um valor "Nulo" no formato SQL, mas não sei como fazer isso em python ou em SQL. Estou descobrindo / aprendendo o ambiente SQL.

Aqui está o meu 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()

Alguém pode me ajudar, por favor.

Obrigado

Respostas

1 Parfait Nov 30 2020 at 02:13

Você parece estar misturando tipos no quadro de dados do Pandas, onde string '',, é combinado com um inteiro na mesma coluna, conforme evidenciado por todos os objecttipos. Em bancos de dados relacionais, você não pode misturar tipos de dados. E a conversão ''para string 'NULL'não resolverá seu problema. No SQL,NULL <> 'NULL'

df.dtypes

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

Portanto, converta colunas em numéricas com pd.to_numericonde string vazia,, ''converte para a NaNqual essa entidade deve ser convertida em NULLentidade 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

Em seguida, execute sua consulta. Na verdade, evite o forloop mais lento com iterrowse 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

Você pode usar Pandas.DataFrame.to_sqlcomo

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

onde appendopção significa inserir novos valores na tabela, se a versão do pandas for 0,15+

DaniMesejo Nov 29 2020 at 21:30

Você poderia fazer:

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)

Resultado

      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

Ou simplesmente,

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

Resultado

      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

Converta para numericas respectivas colunas efillna(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