mysql:insert schreibt nicht in DB trotz commit()

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
loysl
User
Beiträge: 3
Registriert: Mittwoch 20. Oktober 2021, 16:22

Hallo zusammen,
ich bin neu in diesem Forum und experimentiere gerade mit Python (verwende die Version Python 3.10.0) und mySQL (Version 8.0.26).
Trotz intensiver Recherche im Netz und diesem Forum habe ich jetzt keine Lösung für mein aktuelles Problem gefunden.
Deshalb hoffe ich, dass die Profis in diesem Forum mir hier weiterhelfen können.
Dafür schon mal vorab vielen Dank!

Ich habe die Tabelle 'countries' in der DB 'countrydb' erstellt:
"CREATE TABLE countries ("
" country_numeric INTEGER(3),"
" last_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP,"
" country_name_official VARCHAR(255) NOT NULL,"
" PRIMARY KEY (country_numeric)"")")

Die Abfrage showTBL ergibt folgendes Ergebnis:
================ RESTART: Python-Code/CCmysql_showTBL.py ===============
('countries',)

Wenn ich nun meine INSERT-Funktion laufen lasse (siehe weiter unten), erhalte ich als 'rowcount' immer das Ergebnis "-1".
================== RESTART: Python-Code/CCIBANcsv4.py ==================
INSERT INTO countries (country_numeric, country_name_official, last_update) VALUES (%s, '%s', '%s');
004 / Afghanistan
Total number of rows in table: -1
008 / Albania
Total number of rows in table: -1

Beim Versuch über SELECT Werte aus der Tabelle auszulesen, kommt - vermutlich zu recht - das Ergebnis: "NONE".
=============== RESTART: Python- Code/CCmysql_selectTBL.py ==============
SELECT * FROM countries
None

Wie gesagt, ich beschäftige mich erst seit kurzem mit Python, deshalb bitte nicht allzu kritisch auf mein Coding schauen - ich lerne noch ;-)
Wo ist mein Fehler???

===============
from datetime import datetime
import sys
import mysql.connector
import csv

current_timestamp = datetime.now()
insert_timestamp = current_timestamp.strftime('%Y-%m-%d %H:%M:%S')

try:
mydb = mysql.connector.connect(
host="localhost",
user="xxxxxxxx",
password="xxxxxxxx",
database="countrydb")
except:
print ("Keine Verbindung zum Server")
sys.exit(0)

insert_sql = print( "INSERT INTO countries (country_numeric, country_name_official, last_update) VALUES (%s, '%s', '%s');" );

with open('Country-Code-IBAN.csv') as csvfile:
reader = csv.DictReader(csvfile, delimiter = ';')
for row in reader:
print(row['Code-Numeric'], "/", row['Country'])

mycursor = mydb.cursor()

try:
mycursor.execute(insert_sql, [(row['Code-Numeric'], row['Country'], {insert_timestamp})])
mydb.commit()
print("Total number of rows in table: ", mycursor.rowcount)

except mysql.connector.Error as error:
print(f"Oh no, something went wrong.\nIt was: {error}")
mydb.rollback()
sys.exit(0)

mycursor.close()

if mydb.is_connected():
mydb.close()
print("MySQL connection is closed")

sys.exit(0)
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

insert_sql ist None. Denn print gibt nicht den String zurück, den es ausgegeben hat.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Eingerückt wird in Python immer mit 4 Leerzeichen pro Ebene, nicht 2.
Nackte except darf man nicht benutzen, weil damit auch viele Programmierfehler verdeckt werden. Die sprechenden Fehlermeldungen durch nichtssagende zu verdecken, ist auch wenig hilfreich.
sys.exit hat in einem normalen Programm nichts verloren, vor allem nicht, wenn damit immer per Exitcode 0 suggeriert wird, dass alles fehlerfrei lief.

Mit Datenbanken benutzt man immer die passenden Datentypen, ein Datetime-Objekt explizit in einen String umzuwandeln ist daher falsch.

`print` hat als Rückgabewert None, das an insert_sql zu binden ist nicht sinnvoll.
Die Platzhalter in SQL-Statements werden immer ohne Anführungszeichen benutzt.
csv-Dateien öffnet man immer mit explizitem Encoding und newline="".

Die Datenbank heißt zwar mysql aber deshalb muß man nicht an alle Variablennamen ein my anhängen.
Warum steckst Du für execute die Parameter in eine Liste aus einem Tuple, das ein Set enthält? execute braucht genau ein Tuple.

Code: Alles auswählen

import csv
from datetime import datetime
from contextlib import closing
import mysql.connector

current_timestamp = datetime.now()

database = mysql.connector.connect(
    host="localhost",
    user="xxxxxxxx",
    password="xxxxxxxx",
    database="countrydb")

insert_sql = "INSERT INTO countries (country_numeric, country_name_official, last_update) VALUES (%s, %s, %s)"
with closing(database):
    with open('Country-Code-IBAN.csv', encoding="utf8", newline="") as csvfile:
        reader = csv.DictReader(csvfile, delimiter=';')
        for row in reader:
            print(row['Code-Numeric'], "/", row['Country'])
            
            with closing(database.cursor()) as cursor:
                cursor.execute(insert_sql, (row['Code-Numeric'], row['Country'], insert_timestamp))
                database.commit()
                print("Total number of rows in table: ", cursor.rowcount)
loysl
User
Beiträge: 3
Registriert: Mittwoch 20. Oktober 2021, 16:22

__deets__ hat geschrieben: Donnerstag 21. Oktober 2021, 08:52 insert_sql ist None. Denn print gibt nicht den String zurück, den es ausgegeben hat.
... ahhh, Danke!!!

Da hätte ich auch selbst drauf kommen können, aber manchmal sieht man den Wald vor lauter Bäumen nicht ;-)
Habe die Anweisung entsprechend umgebaut und nun funktioniert es!

Super, vielen Dank für die schnelle Rückmeldung.
loysl
User
Beiträge: 3
Registriert: Mittwoch 20. Oktober 2021, 16:22

Sirius3 hat geschrieben: Donnerstag 21. Oktober 2021, 09:35 Eingerückt wird in Python immer mit 4 Leerzeichen pro Ebene, nicht 2.
Nackte except darf man nicht benutzen, weil damit auch viele Programmierfehler verdeckt werden. Die sprechenden Fehlermeldungen durch nichtssagende zu verdecken, ist auch wenig hilfreich.
sys.exit hat in einem normalen Programm nichts verloren, vor allem nicht, wenn damit immer per Exitcode 0 suggeriert wird, dass alles fehlerfrei lief.

Mit Datenbanken benutzt man immer die passenden Datentypen, ein Datetime-Objekt explizit in einen String umzuwandeln ist daher falsch.

`print` hat als Rückgabewert None, das an insert_sql zu binden ist nicht sinnvoll.
Die Platzhalter in SQL-Statements werden immer ohne Anführungszeichen benutzt.
csv-Dateien öffnet man immer mit explizitem Encoding und newline="".

Die Datenbank heißt zwar mysql aber deshalb muß man nicht an alle Variablennamen ein my anhängen.
Warum steckst Du für execute die Parameter in eine Liste aus einem Tuple, das ein Set enthält? execute braucht genau ein Tuple.

Code: Alles auswählen

import csv
from datetime import datetime
from contextlib import closing
import mysql.connector

current_timestamp = datetime.now()

database = mysql.connector.connect(
    host="localhost",
    user="xxxxxxxx",
    password="xxxxxxxx",
    database="countrydb")

insert_sql = "INSERT INTO countries (country_numeric, country_name_official, last_update) VALUES (%s, %s, %s)"
with closing(database):
    with open('Country-Code-IBAN.csv', encoding="utf8", newline="") as csvfile:
        reader = csv.DictReader(csvfile, delimiter=';')
        for row in reader:
            print(row['Code-Numeric'], "/", row['Country'])
            
            with closing(database.cursor()) as cursor:
                cursor.execute(insert_sql, (row['Code-Numeric'], row['Country'], insert_timestamp))
                database.commit()
                print("Total number of rows in table: ", cursor.rowcount)
[/quote]


.. vielen Dank für deine Rückmeldung, ich schaue wie ich das in Zukunft besser machen kann.

Aber wie bereits gesagt:
"Wie gesagt, ich beschäftige mich erst seit kurzem mit Python, deshalb bitte nicht allzu kritisch auf mein Coding schauen - ich lerne noch ;-)"
Antworten