![]() |
Datenbank: Firebird • Version: 3 • Zugriff über: IBDAC
In SQL Zeitraum abfragen
Ich sehe gerade den Wald vor lauter Bäumen nicht: ich habe in einer Tabelle Teilnehmer zu einer Veranstaltung zugeordnet (jede Veranstaltung hat in der Tabelle ein Start- und Ende-Datum). Diese Veranstaltungen laufen häufig auch über den Jahreswechsel. Nun möchte ich z.B. in 2024 die Anzahl der Teilnehmer abfragen, die aktiv an Veranstaltungen teilnehmen und dazu gehören auch die Teilnehmer, die in 2023 gestartet sind und deren Veranstaltung bis irgendwann in 2024 (oder sogar bis 2025) läuft. Veranstaltungen, die bereits in 2023 beendet wurden sollen dabei natürlich nicht mehr berücksichtigt werden. Mit einer Abfrage nach Datumstart und/oder Datumende komme ich da nicht weiter, aber ich sehe gerade nicht, wie es gehen müsste - ich bin für Ideen offen...
Hier mal mein Versuch, 2024 abzufragen: DM1.DataModule1.IBCQuery1.SQL.Add('select VERANSTALTUNGSID from VERANSTALTUNGEN '); DM1.DataModule1.IBCQuery1.SQL.Add('where (DATUMSTART>'+QuotedStr('01.01.'+ComboBox1.Text)+' and DATUMENDE<'+QuotedStr('31.12.'+ComboBox1.Text)+'); Hartmut |
AW: In SQL Zeitraum abfragen
Wenn ich keinen Denkfehler mache, müsste doch dann das Jahr des Startdatums kleiner oder gleich und das Jahr des Enddatums größer oder gleich dem abzufragenden Jahr sein, oder?
Also etwa so:
SQL-Code:
WHERE YEAR(DatumStart) <= Jahr AND YEAR(DatumEnde) >= Jahr
|
AW: In SQL Zeitraum abfragen
Zitat:
also gestartet irgend wann vor dem 31.12.2024 und beendet zwischen dem 1.1. und 31.12. Datum_Start <= 31.12.2024 AND (DatumEnde >= 1.1.2024 AND DatumEnde <= 31.12.2024) |
AW: In SQL Zeitraum abfragen
Hallöle...8-)
Delphi-Quellcode:
...bitte für die Zukunft grundsätzlich Parameter benutzen wegen SQL Injection. :warn:
DM1.DataModule1.IBCQuery1.SQL.Add('select VERANSTALTUNGSID from VERANSTALTUNGEN ');
DM1.DataModule1.IBCQuery1.SQL.Add('where (DATUMSTART>'+QuotedStr('01.01.'+ComboBox1.Text)+' and DATUMENDE<'+QuotedStr('31.12.'+ComboBox1.Text)+'); Grundsätzliche Frage: Ist das "DATUMSTART" Feld ein TimeStamp/Datum Feld oder ein String Feld? :gruebel: Aus SQL abgeleitet...Ich vermute mal ein String Feld. :? Da kommst schwer auf ein richtiges Ergebnis...:| |
AW: In SQL Zeitraum abfragen
Solange zwischen Start- und End-Datum nicht mehr als ein Jahr liegt, fallen dann nicht alle Intervalle in 2024, bei denen das Start- oder das End-Datum in 2024 liegt (beide fällt natürlich auch darunter).
Also, in etwa eine modifizierte Antwort von Detlev:
SQL-Code:
WHERE (YEAR(DatumStart) = :Jahr) OR (YEAR(DatumEnde) = :Jahr)
Nur für den Fall, dass die genannte Einschränkung nicht gilt, müsste man den Fall noch gesondert abfangen:
SQL-Code:
WHERE (YEAR(DatumStart) = :Jahr) OR (YEAR(DatumEnde) = :Jahr) OR ((YEAR(DatumStart) < :Jahr) AND (YEAR(DatumEnde) > :Jahr))
|
AW: In SQL Zeitraum abfragen
Zitat:
|
AW: In SQL Zeitraum abfragen
Danke für eure zahlreichen Tips! Ich werde jetzt mal testen... Und um es noch zu präzisieren: es kann sein das eine Veranstaltung in 2023 beginnt und erst in 2025 endet. Ich muss also abfragen, wieviel Teilnehmer in 2024 betreut werden müssen - das trifft dan ja auf alle zu, die in 2023 begonnen haben und im ganzen Jahr 2024 dabei sind. Zur Info: die Felder Datumstart und Datumende sind in der Tabelle der DB als DATE deklariert (also kein String).
Hartmut |
AW: In SQL Zeitraum abfragen
So, jetzt habe ich mal die Variante von DeddyH getestet (J=2024):
DM1.DataModule1.IBCQuery1.SQL.Add('select VERANSTALTUNGSID from VERANSTALTUNGEN '); DM1.DataModule1.IBCQuery1.SQL.Add('where ((EXTRACT(YEAR from DatumStart) <= '+QuotedStr(IntToStr(J))+') and (EXTRACT(YEAR from DatumEnde) >= '+QuotedStr(IntToStr(J))+')) '); Der code funktioniert zwar - ABER: es ist egal, ob ich für J 2024 oder 2023 oder 2022 eingebe, es kommt immer das gleiche Ergebnis dabei heraus. Da alle Veranstaltungen irgendwie vor/in oder in/nach 2024 starten/enden, kann das so nicht funktionieren... Dann habe ich die Variante von Uwe Raabe getestet: DM1.DataModule1.IBCQuery1.SQL.Add('where ( (EXTRACT(YEAR from DatumStart) = '+QuotedStr(IntToStr(J))+') or (EXTRACT(YEAR from DatumEnde) = '+QuotedStr(IntToStr(J))+') '); DM1.DataModule1.IBCQuery1.SQL.Add('or ((EXTRACT(YEAR from DatumStart) < '+QuotedStr(IntToStr(J))+' and (EXTRACT(YEAR from DatumEnde) > '+QuotedStr(IntToStr(J))+'))) '); Leider auch nicht besser...nur anderes Ergebnis. Mache ich einen Denkfehler oder muss die Abfrage anders verschachtelt werden? Hartmut |
AW: In SQL Zeitraum abfragen
SQL-Code:
Wobei make_date postgreSQL ist. Mit der entsprechenden Firebird Funktion ersetzen (im MSSQL wäre das DateFromParts oder so). Es geht darum, dass man die 2024 dabei ersetzen kann.
Where Datumstart <= make_date(2024, 12, 31) and DatumEnde >= make_date(2024, 1, 1)
// |
AW: In SQL Zeitraum abfragen
SQL-Code:
where Datumstart <= last_day(of year from 2024) and DatumEnde >= first_day( of year from 2024);
|
AW: In SQL Zeitraum abfragen
Zitat:
Könntest du mal konkret die Start- und Ende-Daten der Records auflisten, die deiner Meinung nach nicht im Ergebnis sein sollten? Übrigens: Deine Abfrage macht meiner Meinung nach auch eine falsche Konvertierung beim übergebenen Jahr (J):
Delphi-Quellcode:
DM1.DataModule1.IBCQuery1.SQL.Add('where ((EXTRACT(YEAR from DatumStart) <= '+QuotedStr(IntToStr(J))+') and (EXTRACT(YEAR from DatumEnde) >= '+QuotedStr(IntToStr(J))+')) ');
Da
SQL-Code:
einen SmallInt zurückgibt, solltest du den nicht mit einem String vergleichen. Versuch es mal ohne die Quotes:
EXTRACT(YEAR FROM
Delphi-Quellcode:
DM1.DataModule1.IBCQuery1.SQL.Add('where ((EXTRACT(YEAR FROM DatumStart) <= '+IntToStr(J)+') and (EXTRACT(YEAR FROM DatumEnde) >= '+IntToStr(J)+')) ');
|
AW: In SQL Zeitraum abfragen
mkinzler: ich glaube das war's! Danke.
Allerdings musste ich das anders umsetzen, da die Funktion Last_day wohl erst ab Firebird 4 vorhanden ist...also so habe ich das jetzt gemacht (wobei ComboBox1 eine Auswahliste der Jahre enthält - ComboBox1.Text wäre dann z.B. 2024): where Datumstart <= '+QuotedStr('31.12.'+ComboBox1.Text)+' and DatumEnde >= '+QuotedStr('01.01.'+ComboBox1.Text)+' Hartmut |
AW: In SQL Zeitraum abfragen
Zumindest MySQL/MariaDB kennen auch den Operator "between..and". Zusammen mit Parametern ergibt das dann ein gut lesbares Stück Code:
Delphi-Quellcode:
Damit wäre es dann sogar auf die Millisekunde genau. Falls nicht nötig, gäbe es auch noch EncodeDate(), womit man sich die Uhrzeit-Parameter spart. (Es ist (natürlich...) nicht dokumentiert, aber ich gehe davon aus, dass hier immer die Uhrzeit 00:00:00:0000 implizit zurückgegeben wird.)
DM1.DataModule1.IBCQuery1.SQL.Text := 'SELECT * FROM `Tabelle` WHERE `Datumsfeld` BETWEEN :dt1 AND :dt2';
DM1.DataModule1.IBCQuery1.ParamByName('dt1').AsDateTime := EncodeDateTime(StrToInt(ComboBox1.Text), 12, 31, 23, 59, 59, 999); DM1.DataModule1.IBCQuery1.ParamByName('dt2').AsDateTime := EncodeDateTime(StrToInt(ComboBox2.Text), 1, 1, 0, 0, 0, 0); Edit: Schon spät. Geht natürlich nur, wenn das Datumsfeld für beide Grenzbedingungen dasselbe ist. Sorry! Aber Parameter finde ich dennoch deutlich hübscher (und sicherer!) |
AW: In SQL Zeitraum abfragen
Kann mir mal irgendjemand erklären, wieso eine zu vergleichende Zahl vor dem Vergleich in einen String gewandelt wird? Nochmal: verwende SQL-Parameter, mit diesem ganzen Gequote bekommst Du nicht nur falsche Ergebnisse, sondern bist auch anfällig für SQL-Injection.
Delphi-Quellcode:
Das sollte alle Veranstaltungen liefern, die im betreffenden Jahr begonnen haben oder enden bzw. die das komplette Jahr überlappen.
DM1.DataModule1.IBCQuery1.SQL.Text := 'select VERANSTALTUNGSID from VERANSTALTUNGEN where EXTRACT(YEAR from DatumStart) <= :Anfang and EXTRACT(YEAR from DatumEnde) >= :Ende';
DM1.DataModule1.IBCQuery1.ParamByName('Anfang').AsInteger := J; DM1.DataModule1.IBCQuery1.ParamByName('Ende').AsInteger := J; |
AW: In SQL Zeitraum abfragen
Zitat:
- vor JAHR begonnen und nach JAHR beendet - vor JAHR begonnen und im JAHR beendet - im JAHR begonnen und nach JAHR beendet - im JAHR begonnen und im JAHR beendet Da du alle willst: mit OR verknüpfen. SQL Umsetzung ist dann trivial. |
AW: In SQL Zeitraum abfragen
DeddyH: ja, natürlich sieht das besser und eleganter aus mit Parametern...und kommt bei mir auch beim "Finetuning" - ich wollte nur erstmal testen, ob die Ergebnisse passen, daher die "String-Orgie":oops:.
TigerLilly: das werde ich dann als nächstes testen, damit ich auch wirklich alle Varianten ermitteln kann - danke. Hartmut |
AW: In SQL Zeitraum abfragen
Im Prinzip werden Veranstaltungen gesucht, deren Zeitraum sich mit einem angegebenen Zeitraum überschneiden.
Das es sich dabei um Jahresanfang und Ende eines bestimmten Jahres handelt, ist nur ein Spezialfall, den man im SQL nicht gesondert behandeln muss. Sind 'datumstart' und 'datumende' reine Datumsfelder, benötigt man den Zeitanteil bei den Parametern nicht.
Delphi-Quellcode:
var Jahr := StrToInt(ComboBoxJahr.Text);
Query.SQL.Text := 'select * from verabstaltungen where (datumstart <= :bis) and ((datumende is null) or (datumende >= :von))'; Query.ParamByName('von').AsDateTime := EncodeDateTime(Jahr, 1, 1, 0, 0, 0, 0); Query.ParamByName('bis').AsDateTime := EncodeDateTime(Jahr, 12, 31, 23, 59, 59, 999); |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:36 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz