Ich versuche, diese Abfrage zum Laufen zu bringen, aber sie funktioniert nicht wie erwartet.
In der Tabelle ist ein als Text formatiertes Datumsfeld (kann es nicht ändern) und ich muss diese Spalte filtern.
Termine aussehen
11/03/2022 (d/m/Y)
Meine Abfrage sieht aus wie
session.query(DBGEUK)\
.filter(DBGEUK.VALIDATOR == '58')\
.filter(func.CDate(DBGEUK.DATE) <= datetime.now())\
.all()
Es gibt insgesamt 24 Einträge. Wenn ich die obige Abfrage ausführe und DBGEUK.DATE + datetime.now ausdrucke, sind diese 9 Einträge mein Ergebnis.
27/03/2022 2022-03-28 19:06:49.465406
27/03/2022 2022-03-28 19:06:49.480988
27/03/2022 2022-03-28 19:06:49.480988
27/03/2022 2022-03-28 19:06:49.480988
28/03/2022 2022-03-28 19:06:49.480988
28/03/2022 2022-03-28 19:06:49.480988
28/03/2022 2022-03-28 19:06:49.480988
28/03/2022 2022-03-28 19:06:49.481612
28/03/2022 2022-03-28 19:06:49.481727
Wenn ich die Abfrage auf größer als >= ändere, bekomme ich die anderen 15 Einträge
04/03/2022 2022-03-28 19:09:09.030659
04/03/2022 2022-03-28 19:09:09.031659
04/03/2022 2022-03-28 19:09:09.031659
04/03/2022 2022-03-28 19:09:09.031659
04/03/2022 2022-03-28 19:09:09.031659
05/03/2022 2022-03-28 19:09:09.031659
05/03/2022 2022-03-28 19:09:09.031659
05/03/2022 2022-03-28 19:09:09.031659
05/03/2022 2022-03-28 19:09:09.032657
11/03/2022 2022-03-28 19:09:09.032657
12/03/2022 2022-03-28 19:09:09.032657
11/03/2022 2022-03-28 19:09:09.032657
11/03/2022 2022-03-28 19:09:09.032657
09/03/2022 2022-03-28 19:09:09.033654
09/03/2022 2022-03-28 19:09:09.033654
Vielen Dank für Ihre Hilfe im Voraus.
Lösung des Problems
Die CDate()
Funktion versucht, Datumszeichenfolgenliterale gemäß den Datumsformatierungseinstellungen in der Windows-Systemsteuerung zu interpretieren. Bei einer „kurzen Datumseinstellung" von MM/dd/yyyy
wird CDate("03/07/2022")
der 7. März 2022 ausgewertet. Bei einer „kurzen Datumseinstellung" von dd/MM/yyyy
wird CDate("03/07/2022")
der 3. Juli 2022 ausgewertet.
Wenn die Datumszeichenfolge jedoch ein ungültiges Datum darstellt CDate()
, ist "hilfreich" und gibt ein gültiges Datum mit dem anderen Format zurück. In beiden oben genannten Fällen CDate("14/03/2022")
wird der 14. März 2022 ausgewertet.
Das bedeutet leider
Daher müssen wir in diesem Fall vermeiden, CDate()
die Datumszeichenfolge selbst zu verwenden und zu analysieren:
from datetime import datetime
from sqlalchemy import create_engine, Column, String, select, func
from sqlalchemy.engine import URL
from sqlalchemy.orm import declarative_base, Session
accdb_path = r"C:\Users\Public\test\sqlalchemy-access\gord_test.accdb"
connection_string = (
"DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};"
f"DBQ={accdb_path};"
"ExtendedAnsiSQL=1;"
)
connection_url = URL.create(
"access+pyodbc", query={"odbc_connect": connection_string}
)
engine = create_engine(connection_url)
Base = declarative_base()
class DBGEUK(Base):
__tablename__ = "so71651145"
DATE = Column(String(10), primary_key=True)
def __repr__(self):
return f"<DBGEUK(DATE='{self.DATE}')>"
# create test environment
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
with Session(engine) as session:
# example data
session.add_all(
[
# How CDate() interprets the string
# based on Windows' short date format:
#
# dd/MM/yyyy MM/dd/yyyy
# ------------ ------------
DBGEUK(DATE="07/03/2022"), # Mar 7, 2022 Jul 3, 2022
DBGEUK(DATE="14/03/2022"), # Mar 14, 2022 Mar 14, 2022
DBGEUK(DATE="03/07/2022"), # Jul 3, 2022 Mar 7, 2022
DBGEUK(DATE="31/12/2022"), # Dec 31, 2022 Dec 31, 2022
]
)
session.commit()
# (for future readers of this answer)
print(datetime.now()) # 2022-03-29 08:44:00.512366
# original query
qry = select(DBGEUK).filter(func.CDate(DBGEUK.DATE) <= datetime.now())
results = session.scalars(qry).all()
print(results)
# [<DBGEUK(DATE='14/03/2022')>, <DBGEUK(DATE='03/07/2022')>]
#
# with Windows' short date format set to MM/dd/yyyy, CDate() interprets
# the second value as March 7, not July 3
# corrected query
qry = select(DBGEUK).filter(
func.DateSerial(
func.CInt(func.Mid(DBGEUK.DATE, 7, 4)), # year
func.CInt(func.Mid(DBGEUK.DATE, 4, 2)), # month
func.CInt(func.Mid(DBGEUK.DATE, 1, 2)), # day
)
<= datetime.now()
)
results = session.scalars(qry).all()
print(results)
# [<DBGEUK(DATE='07/03/2022')>, <DBGEUK(DATE='14/03/2022')>]
#
# all good
Keine Kommentare:
Kommentar veröffentlichen