pyodbc ValueError: hour must be in 0..23

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Hallo zusammen,
zuerst meinen respekt an das Forum, tolle arbeit.

Leider habe ich bei einer Datenbankabfrage zu einer AS400 ein Problem:

Connection zur AS400:

connection = pyodbc.connect(
driver='{iSeries Access ODBC Driver}',
system='172.16.0.3',
uid='user',
pwd='password')
c1 = connection.cursor()

Die Abfrage lautet:
ausgabe = c1.execute('SELECT * from WAWBRUDTA.FERKPU WHERE FKAUNR = ?', ProdNr).fetchone()[4]

Jetzt das Problem:
Auf Recher A läuft alles ohne Probleme, auf den Rechnern B und C erhalte ich die Fehlermeldung:
ValueError: hour must be in 0..23
Andere Abfragen zur AS400 laufen ohne Probleme auf allen Systemen.

Zu den Systemen (alle gleich):
Die Rechner: Win 10 64 Bit
Python: 3.7.2 (32 Bit)
pyodbc: 4.0.25
iSeries odbc Treiber: 13.00.1.00 (32 und 64 Bit)

Hat jemand eine Idee dazu ?
Bin für jeden Hinweis dankbar

Gruß Marc
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Scheint als würde das beim Konvertieren zu einer DateTime nicht funktionieren. Kannst du bitte einmal den ganzen Code posten?
__deets__
User
Beiträge: 14542
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich kann mir nur vorstellen, dass es etwas mit Zeitzonen/Format-Einstellungen zu tun hat, die da irgendwie nicht passen. Damit versucht dann der eine Rechner, die 15:00 als 3PM los zu werden, und das bringt die DB aus dem Tritt. Falls die Datenbank und der Treiber da Moeglichkeiten haben, abzufragen, wie sie sich fuehlen, wuerde ich das mal machen, und vergleichen.
Benutzeravatar
__blackjack__
User
Beiträge: 13112
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@marju: ``SELECT *`` nur um dann das fünfte Element vom Ergebnistupel zu nehmen ist unsinnig. Es wäre verständlicher wenn Du die Spalte einfach namentlich im `SELECT` angeben würdest. In der Hoffnung das die Spalten bessere Namen haben als `WAWBRUDTA.FERKPU` (wtf‽) bring das dem Leser einen Mehrwert. Und auch sonst sind * beim SELECT nicht so toll, weil nicht robust gegen Änderungen bei den Spalten in der Datenbank.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Also `prod_nr` statt `ProdNr`. Wobei besser wäre `product_number` (oder `produktnummer`) statt kryptischer Abkürzungen. Und einbuchstabige Namen sind nicht gut, und mit angehängten Nummern, das geht gar nicht. Wenn man ein Verbindungsobjekt hat, sollte man das `connection` nennen.

Ansonsten wäre ein betroffener Datensatz interessant.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Hallo zusammen,
danke für die Infos. Die Zeitzonen/Format-Einstellungen sind auch auf allen Rechnern gleich.
Leider tritt der Fehler in sämtlichen Variationen der Abfrage auf.
Hier ein Beispielcode, alle Aufträge für 2019, der nur auf dem einen Rechner läuft (habe die Hinweise von blackjack schon mal eingepflegt, danke dafür).
Das fünfte Element vom Ergebinstupel hatte ich nur genommen um zu testen ob wenigstens ein Wert klappt. Aber selbt das leider nicht.
Die Tabellennamen sind vom ERP System leider vorgegeben und leider sehr kryptisch.

Der Beispielcode (extra kurz und knapp).

import pyodbc
import sys
import datetime

connection = pyodbc.connect(
driver='{iSeries Access ODBC Driver}',
system='172.16.0.3',
uid='user',
pwd='password')
as400daten = connection.cursor()

auftragseingabe = int (input("Bitte geben Sie die Auftragsnummer ein: "))
as400daten.execute("select * From WAWBRUDTA.FERKPU WHERE FKAUNR >= '1900000'")
for row in as400daten:
print("Auftragsnummer: ", row[1])
print("Artikelnummer: ", row[4])
print("Produktionsnummer:", row[10])
print("_________________________________")


Ausgabe auf dem einen Rechner:
Auftragsnummer: 1905976
Artikelnummer: 1905960
Produktionsnummer: 14G624C-1429
_________________________________

Ausgabe auf den anderen Rechnern:
for row in as400daten:
ValueError: hour must be in 0..23

Wenn ich print (row) ausführe, erster Datensatz:
('001', Decimal('1906834'), 'FP0', '10170 ', Decimal('1906813'), Decimal('1'), datetime.date(2020, 1, 1), 'Lochbrett Schablone ', '00100 ', 'J', '00P6230-0027 ', ' ', ' ', ' ', '00P6230-0027 ', '500 ', ' ', datetime.date(2020, 1, 1), Decimal('2020'), Decimal('1'), datetime.date(2019, 12, 12), Decimal('0'), Decimal('0'), Decimal('0'), datetime.date(1, 1, 1), Decimal('0'), Decimal('0'), Decimal('0'), datetime.date(2019, 12, 31), Decimal('0'), Decimal('2019'), Decimal('53'), datetime.date(1, 1, 1), Decimal('0'), Decimal('0'), Decimal('0'), datetime.date(2019, 12, 12), Decimal('2019'), Decimal('50'), ' ', ' ', ' ', Decimal('0'), Decimal('0'), Decimal('1'), Decimal('1'), Decimal('150.0000'), Decimal('0'), Decimal('0'), Decimal('150.0000'), Decimal('0'), Decimal('0'), Decimal('0'), '01 ', '001 ', '02020300330', ' ', 'F01', 'F02', 'F03', 'Steuerkarte ', 'B', '0', '0', ' ', '1', Decimal('0'), Decimal('12.0000'), Decimal('0'), Decimal('0'), Decimal('150.0000'), '00P6230-0027 ', 'N', ' ', '0', Decimal('0'), ' ', 'A', '0', '1', '1', '1', '0', ' ', '2', '1', ' ', ' ', ' ', ' ', 'A', ' ', 'J', ' ', ' ', datetime.date(1, 1, 1), 'ADG', datetime.date(2019, 12, 6), ' ')
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Im SQL log wird es jetzt merkwürdig.

Auf dem Rechner wo es läuft ist eine Fehlermeldung beim MS ODBC Treiber:

FirstModul 1824-6c EXIT SQLDriverConnectW with return code 1 (SQL_SUCCESS_WITH_INFO)
HDBC 0x01107A78
HWND 0x00000000
WCHAR * 0x68872440 [ -3] "******\ 0"
SWORD -3
WCHAR * 0x68872440 <Invalid buffer length!> [-3]
SWORD -3
SWORD * 0x00000000
UWORD 0 <SQL_DRIVER_NOPROMPT>

DIAG [01S00] [Microsoft][ODBC Driver Manager] Ungültiges Attribut für die Verbindungszeichenfolge (0)

DIAG [01000] [IBM][System i Access ODBC-Treiber][DB2 für i5/OS]PWS0082 - Bibliothek(en) der Bibliotheksliste nicht hinzugefgt. (51301)

FirstModul 1824-6c ENTER SQLSetConnectAttr
SQLHDBC 0x01107A78
SQLINTEGER 102 <SQL_ATTR_AUTOCOMMIT>
SQLPOINTER 0 <SQL_AUTOCOMMIT_OFF>
SQLINTEGER -5


Der Recher wo es nicht läuft da sieht es wie folgt aus:

pythonw.exe -c 1494-1330 EXIT SQLDriverConnectW with return code 1 (SQL_SUCCESS_WITH_INFO)
HDBC 0x01B57498
HWND 0x00000000
WCHAR * 0x703D2440 [ -3] "******\ 0"
SWORD -3
WCHAR * 0x703D2440 <Invalid buffer length!> [-3]
SWORD -3
SWORD * 0x00000000
UWORD 0 <SQL_DRIVER_NOPROMPT>

DIAG [01000] [IBM][System i Access ODBC-Treiber][DB2 für i5/OS]PWS0082 - Bibliothek(en) der Bibliotheksliste nicht hinzugefgt. (51301)

pythonw.exe -c 1494-1330 ENTER SQLSetConnectAttr
SQLHDBC 0x01B57498
SQLINTEGER 102 <SQL_ATTR_AUTOCOMMIT>
SQLPOINTER 0 <SQL_AUTOCOMMIT_OFF>
SQLINTEGER -5

Hat jemand eine Idee dazu????
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Habe im Logfile mit dem MS Fehler alle Datensätze gefunden.
Im Logfile wo der MS Fehler nicht vorkommt, ist nur ein Teil der Datensätze vorhanden.

Hier wird wohl das Problem liegen.
Benutzeravatar
__blackjack__
User
Beiträge: 13112
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@marju: Nur ein einzelnes Element aus dem Datensatz zu nehmen verhindert natürlich nicht das irgendeines der Elemente einen Fehler bei der Konvertierung auslösen kann, denn das passiert ja immer für alle *vor* dem Zugriff auf einzelne Elemente und nicht erst wenn man auf ein Element zugreift.

Interessant wäre halt mal genau einen Datensatz zu sehen bei dem es die Fehlermeldung gibt. Wenn Du da beispielsweise noch ein ORDER BY anhängst das nach der Auftragsnummer zu sortiert, müsste sich das ja leicht eingrenzen lassen.

Ansonsten kann der Unterschied natürlich noch in der Konfiguration liegen wie der Datenbanktreiber auf dem System eingebunden ist. Da kann man ja auch verschiedene Einstellungen machen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

In dem Beispieldatensarz obem sehe ich keine Uhrzeit.
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Hallo,
das ist ja das Problem, es steht keine Uhrzeit in den Datensätzen drin. Dennoch kommt der Fehler.
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Nur damit ich das richtig verstehe:
Auf Rechner A bekommst du keine Fehlermeldung, aber es fehlen Datensätze.
Auf Rechner B bekommst du eine Fehlermeldung und gar keine Datensätze.

Korrekt?

Was ist, wenn du die ODBC-Datenquelle direkt in Windows anlegst und dann über die DSN ansprichst? Da du ein 64-bit Betriebssystem verwendest aber den 32-bit Treiber musst du die Datenquelle über %WINDIR%\SysWOW64\odbcad32.exe anlegen.
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Nicht ganz,
Rechner A bekommt keine Fehlermeldung und alle Datensätze
Rechner B bekommt die Fehlermeldung und im SQL Log nicht alle Datensätze.

Auf beiden Rechnern ist Win 10 64 Bit.
Python in 32Bit
iseries ODBC Treiber in 64 und 32 Bit.
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Interessant wäre, welche Typen hinter den Spalten verbergen und ob da überhaupt Dinge gefunden werden und wenn ja, bei welchem Datensatz es stoppt:

Code: Alles auswählen

import pyodbc
connection = pyodbc.connect(
    driver='{iSeries Access ODBC Driver}',
    system='172.16.0.3',
    uid='user',
    pwd='password')
cursor = connection.cursor()
cursor.execute("SELECT *  FROM WAWBRUDTA.FERKPU WHERE FKAUNR >= '1900000' ORDER BY FKAUNR")
print("COLUMNS:")
for column in cursor.description:
    print(f"{column[0]} {column[1]}")
print("ROWS:")
numbers_seen = []
try:
    for row in cursor:
        numbers_seen.append(row.FKAUNR)
except ValueError:
    raise
finally:
    print(f"I have seen {len(numbers_seen)} numbers.")
    if len(numbers_seen) > 0:
        print(f"The last one was: {numbers_seen[-1]}")
    if len(numbers_seen) > 1:
        print(f"      before was: {numbers_seen[-2]}")
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Hier das Ergebniss:
COLUMNS:
FKFIRM <class 'str'>
FKAUNR <class 'decimal.Decimal'>
FKARSL <class 'str'>
FKADRN <class 'str'>
FKEAUN <class 'decimal.Decimal'>
FKEPOS <class 'decimal.Decimal'>
FKEADT <class 'datetime.date'>
FKZNR1 <class 'str'>
FKZNR2 <class 'str'>
FKTLFE <class 'str'>
FKARTN <class 'str'>
FKARVA <class 'str'>
FKLGCG <class 'str'>
FKVPEH <class 'str'>
FKARBP <class 'str'>
FKPRDS <class 'str'>
FKPRLT <class 'str'>
FKATDT <class 'datetime.date'>
FKATJA <class 'decimal.Decimal'>
FKATWO <class 'decimal.Decimal'>
FKSTDT <class 'datetime.date'>
FKSTZE <class 'decimal.Decimal'>
FKSTJA <class 'decimal.Decimal'>
FKSTWO <class 'decimal.Decimal'>
FKESDT <class 'datetime.date'>
FKESZE <class 'decimal.Decimal'>
FKESJA <class 'decimal.Decimal'>
FKESWO <class 'decimal.Decimal'>
FKETDT <class 'datetime.date'>
FKETZE <class 'decimal.Decimal'>
FKETJA <class 'decimal.Decimal'>
FKETWO <class 'decimal.Decimal'>
FKEEDT <class 'datetime.date'>
FKEEZE <class 'decimal.Decimal'>
FKEEJA <class 'decimal.Decimal'>
FKEEWO <class 'decimal.Decimal'>
FKWVDT <class 'datetime.date'>
FKWVJA <class 'decimal.Decimal'>
FKWVWO <class 'decimal.Decimal'>
FKKOST <class 'str'>
FKKOTR <class 'str'>
FKPJNR <class 'str'>
FKBSAU <class 'decimal.Decimal'>
FKAZFG <class 'decimal.Decimal'>
FKAZPR <class 'decimal.Decimal'>
FKAZOP <class 'decimal.Decimal'>
FKPRMG <class 'decimal.Decimal'>
FKMGZP <class 'decimal.Decimal'>
FKMGBP <class 'decimal.Decimal'>
FKMGIP <class 'decimal.Decimal'>
FKFEEK <class 'decimal.Decimal'>
FKKALW <class 'decimal.Decimal'>
FKKHKO <class 'decimal.Decimal'>
FKLGME <class 'str'>
FKLGZB <class 'str'>
FKFGST <class 'str'>
FKFGDT <class 'str'>
FKBUSL <class 'str'>
FKBUS1 <class 'str'>
FKBUS2 <class 'str'>
FKLINR <class 'str'>
FKSKZ1 <class 'str'>
FKSKZ2 <class 'str'>
FKSKZ3 <class 'str'>
FKSKZ4 <class 'str'>
FKLGAU <class 'str'>
FKLCF1 <class 'decimal.Decimal'>
FKLCF2 <class 'decimal.Decimal'>
FKLCF3 <class 'decimal.Decimal'>
FKLCF4 <class 'decimal.Decimal'>
FKLCF5 <class 'decimal.Decimal'>
FKLGAR <class 'str'>
FKVPKZ <class 'str'>
FKCGDF <class 'str'>
FKCGKZ <class 'str'>
FKAUVS <class 'decimal.Decimal'>
FKSCHI <class 'str'>
FKSTA1 <class 'str'>
FKSTA2 <class 'str'>
FKSTA3 <class 'str'>
FKSTA4 <class 'str'>
FKSTA5 <class 'str'>
FKSTA6 <class 'str'>
FKSTA7 <class 'str'>
FKST01 <class 'str'>
FKST02 <class 'str'>
FKST03 <class 'str'>
FKST04 <class 'str'>
FKST05 <class 'str'>
FKST06 <class 'str'>
FKST07 <class 'str'>
FKST08 <class 'str'>
FKST09 <class 'str'>
FKST10 <class 'str'>
FKAPID <class 'str'>
FKADAT <class 'datetime.date'>
FKEPID <class 'str'>
FKEDAT <class 'datetime.date'>
FKWSID <class 'str'>
ROWS:
I have seen 0 numbers.
Traceback (most recent call last):
File "Z:\Fertigung\THT-Technik\Loetprogrammuebersicht\Test\Test.py", line 15, in <module>
for row in cursor:
ValueError: hour must be in 0..23
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Dann schauen wir mal, ob wir das auf ein Feld eingrenzen können:

Code: Alles auswählen

with pyodbc.connect(
    driver='{iSeries Access ODBC Driver}',
    system='172.16.0.3',
    uid='user',
    pwd='password')as connection:
    cursor = connection.cursor()
    cursor.execute("SELECT *  FROM WAWBRUDTA.FERKPU WHERE FKAUNR >= '1900000' ORDER BY FKAUNR")
    columns = (column[0] for column in cursor.description)
    for column in columns:
        print(f"Testing {column}")
        cursor.execute(f"SELECT {column} FROM WAWBRUDTA.FERKPU WHERE FKAUNR >= '1900000' ORDER BY FKAUNR")
        cursor.fetchone()
Edit: Verbindungsdaten korrigiert
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Ergebnis:
Testing FKFIRM
Testing FKAUNR
Testing FKARSL
Testing FKADRN
Testing FKEAUN
Testing FKEPOS
Testing FKEADT
Traceback (most recent call last):
File "Z:\Fertigung\THT-Technik\Loetprogrammuebersicht\Test\Test1.py", line 13, in <module>
cursor.fetchone()
ValueError: hour must be in 0..23
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Testing FKFIRM
Testing FKAUNR
Testing FKARSL
Testing FKADRN
Testing FKEAUN
Testing FKEPOS
Testing FKEADT
Traceback (most recent call last):
File "Z:\Fertigung\THT-Technik\Loetprogrammuebersicht\Test\Test1.py", line 13, in <module>
cursor.fetchone()
ValueError: hour must be in 0..23
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Testing FKFIRM
Testing FKAUNR
Testing FKARSL
Testing FKADRN
Testing FKEAUN
Testing FKEPOS
Testing FKEADT
Traceback (most recent call last):
File "Z:\Fertigung\THT-Technik\Loetprogrammuebersicht\Test\Test1.py", line 13, in <module>
cursor.fetchone()
ValueError: hour must be in 0..23
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Testing FKFIRM
Testing FKAUNR
Testing FKARSL
Testing FKADRN
Testing FKEAUN
Testing FKEPOS
Testing FKEADT
Traceback (most recent call last):
File "Z:\Fertigung\THT-Technik\Loetprogrammuebersicht\Test\Test1.py", line 13, in <module>
cursor.fetchone()
ValueError: hour must be in 0..23
marju
User
Beiträge: 21
Registriert: Donnerstag 12. Dezember 2019, 13:26
Wohnort: Bad Pyrmont

Ich habe gerade bei der schnellen Durchsicht der Datensätze (ca. 35000) für FKEADT (Externes Lieferdatum) foldendes gefunden:
Datum: 11.09.2014
bei einigen Datensätzen steht allerdings:
01.01.0001
Antworten