Entwickler-Ecke

Datenbanken - SQL Abfrage per Quartal


Arne Danikowski - Di 12.05.09 17:43
Titel: SQL Abfrage per Quartal
Hallo,

ich habe in einer Accessdatenbank Datensätze, die nach Datum Indiziert sind.

Aubau der Tabelle:

Feld Art
ID Autowert
Datum Datum (Index)
Kundennummer Integer
Techniker Text
Zeiteinheiten Integer
Bemerkung Memo


Über eine Auswahl (z.B. 2 Comboboxen) soll das Jahr und das Quartal bestimmt werden, wonach die Datensätze gefiltert werden sollen.

Quartal I = 01.01.XX - 31.03.XX
Quartal II = 01.04.XX - 31.03.XX
Quartal III = 01.07.XX - 30.09.XX
Quartal IV = 01.10.XX - 31.12.XX


Ich möchte nun nur Datensätze anzeigen, die folgenden Kreterien entsprechen:

a.) Nur Kundennummer xxx
b.) Jahr aus Combobox I
c.) Quartal aus Combobox II

Also ich bekomme die SQL Abfrage nicht hin. Da ich schon tausend Sachen ausprobiert habe, poste ich hier auch keinen Code.

Vieleicht weis hier jemand Rat.

vd im voraus


ffgorcky - Di 12.05.09 17:55

Naja, ich gehe also mal davon aus, dass Du weißt, wie Du eine SQL-Abfrage an die Datenbank schickst. - Oder liegt das schon daran?
Die Abfrage über die Kundennummer ist doch noch richtig einfach:

SQL-Anweisung
1:
select * from Automieten where Kundennummer=222                    

...wobei ich denke, dass Du das ganze ja nicht fest Codieren möchtest, also müsstest Du das ganze dann so machen:

Delphi-Quelltext
1:
SQLQuery:='select * from Automieten where Kundennummer='+EditKundennummer.Value;                    


Delete - Di 12.05.09 18:02

Ohne besondere Fehlerbehandlung:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
var y,m1,m2,d1,d2: Word;
    von, bis: TDate;
begin
  //die ComboBox cbbQuartal enthält die Items I bis IV
  case cbbQuartal.ItemIndex of
    0begin
         m1 := 1;
         d1 := 1;
         m2 := 3;
         d2 := 31;
       end;
    1begin
         m1 := 4;
         d1 := 1;
         m2 := 6;
         d2 := 30;
       end;
    2begin
         m1 := 7;
         d1 := 1;
         m2 := 9;
         d2 := 30;
       end;
    3begin
         m1 := 10;
         d1 := 1;
         m2 := 12;
         d2 := 31;
       end;
  end;
  //die ComboBox cbbJahr enthält nur Items mit den Jahreszahlen
  y := StrToInt(cbbJahr.Items[cbbJahr.ItemIndex]);
  von := EncodeDate(y,m1,d1);
  bis := EncodeDate(y,m2,d2);
  ADOQuery1.SQL.Text := 'SELECT * FROM Tabelle WHERE (Datum BETWEEN :von AND :bis) AND (Kundennummer=:nr)';
  ADOQuery1.Parameters.ParamByName('von').Value := von;
  ADOQuery1.Parameters.ParamByName('bis').Value := bis;
  ADOQuery1.Parameters.ParamByName('nr').Value := Kundennummer;
  ADOQuery1.Open;


Arne Danikowski - Di 12.05.09 18:20

Vielen Dank für die schnelle Antworten,

habe das mal so gemacht:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
procedure Twartungdrucken.BitBtn1Click(Sender: TObject);
var y,m1,m2,d1,d2: Word;
    von, bis: TDate;
    KDNR:String;
begin
          case qualtalcombo.ItemIndex of
    0begin
         m1 := 1;
         d1 := 1;
         m2 := 3;
         d2 := 31;
       end;
    1begin
         m1 := 4;
         d1 := 1;
         m2 := 6;
         d2 := 30;
       end;
    2begin
         m1 := 7;
         d1 := 1;
         m2 := 9;
         d2 := 30;
       end;
    3begin
         m1 := 10;
         d1 := 1;
         m2 := 12;
         d2 := 31;
       end;
  end;
  //die ComboBox cbbJahr enthält nur Items mit den Jahreszahlen
  y := StrToInt(JahrCombo.Items[JahrCombo.ItemIndex]);
  von := EncodeDate(y,m1,d1);
  bis := EncodeDate(y,m2,d2);
  KDNR:=DM.EinsatzADOQuery.FieldByName('Kundennummer').AsString;
  DM.EinsatzADOQuery.SQL.Text := 'SELECT * FROM EINSATZ WHERE (Datum BETWEEN :von AND :bis) AND (Kundennummer=:nr)';
  DM.EinsatzADOQuery.Parameters.ParamByName('von').Value := von;
  DM.EinsatzADOQuery.Parameters.ParamByName('bis').Value := bis;
  DM.EinsatzADOQuery.Parameters.ParamByName('nr').Value := KDNR;
  DM.EinsatzADOQuery.Open;
  RvProject1.Open;
  RvProject1.Execute;
 end;


Allerdings bekomme ich beim Ausführen eine Fehlermeldung:

"Datentypen im Kreterienausdruck unverträglich"

Der Fehler kommt, sobald die Query geöffnet wird.


ffgorcky - Di 12.05.09 18:33

Also ich hätte das dann so gelöst (wobei ich leider nicht weiß, ob das wirklich so eine "saubere" Lösung ist):

Delphi-Quelltext
1:
  DM.EinsatzADOQuery.SQL.Text := 'SELECT * FROM EINSATZ WHERE (Datum BETWEEN '+von+' AND '+bis+') AND (Kundennummer='+KDNR+')';                    


Ich weiß allerdings nicht, ob die Lösung wirklich gut ist, oder doch eher Deine Lösung mit den SQL-Variablen besser ist.


Delete - Di 12.05.09 18:39

Dann versuch es mal mit

Delphi-Quelltext
1:
2:
DM.EinsatzADOQuery.Parameters.ParamByName('von').AsDate := von;
DM.EinsatzADOQuery.Parameters.ParamByName('bis').AsDate := bis;


[edit] Moment mal, wieso fragst Du die Kundennummer als String ab? Da liegt der Fehler. [/edit]


Arne Danikowski - Mi 13.05.09 09:06

Hallo,

nochmal danke für die Antwort.

AsDate gibt es nicht.
Ich habe aber mal die Daten in String umgewandelt und man siehe es funktioniert.
Der Vollständigkeit das ganze Listing noch einmal:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
procedure Twartungdrucken.BitBtn1Click(Sender: TObject);
var y,m1,m2,d1,d2: Word;
    von, bis: TDate;
    KDNR,anfang,ende:String;
begin
          case qualtalcombo.ItemIndex of
    0begin
         m1 := 1;
         d1 := 1;
         m2 := 3;
         d2 := 31;
       end;
    1begin
         m1 := 4;
         d1 := 1;
         m2 := 6;
         d2 := 30;
       end;
    2begin
         m1 := 7;
         d1 := 1;
         m2 := 9;
         d2 := 30;
       end;
    3begin
         m1 := 10;
         d1 := 1;
         m2 := 12;
         d2 := 31;
       end;
  end;

  y := StrToInt(JahrCombo.Items[JahrCombo.ItemIndex]);
 
  von := EncodeDate(y,m1,d1);
  bis := EncodeDate(y,m2,d2);
  
  anfang:=DatetoStr(von);
  ende:=DateToStr(bis);
  
  KDNR:=DM.EinsatzADOQuery.FieldByName('Kundennummer').AsString;
  DM.EinsatzADOQuery.SQL.Text := 'SELECT * FROM EINSATZ WHERE (Datum BETWEEN :von AND :bis) AND (Kundennummer=:nr)';
  DM.EinsatzADOQuery.Parameters.ParamByName('von').Value := anfang;
  DM.EinsatzADOQuery.Parameters.ParamByName('bis').Value := ende;
  DM.EinsatzADOQuery.Parameters.ParamByName('nr').Value := KDNR;
  DM.EinsatzADOQuery.Open;
  
  RvProject1.Open;
  RvProject1.Execute;
 end;


Bis dann !! Hat sehr geholfen.


Delete - Mi 13.05.09 09:23

Und wenn Du überall den Cast weglässt (also statt AsString Value verwendest)? Sofern die Kundennummer in beiden Tabellen nummerisch ist, sollte das auch funktionieren.


jaevencooler - Mi 13.05.09 10:25

Guten Tach auch,

also ich bin kein Access Profi, aber auf einer Oracle würde das so gehen :


SELECT * from <<Deiner Tabelle>>

where to_number(to_char(Datum, 'q')) = :Quartal



to_char : wandelt das Datum in einen formatierten String, das Format ist in diesem Fall 'q'
to_number : wandelt das Ergebnis von String in Number (kann amn auch weg lassen und auf String vergleichen.

Die vergelichbaren Routinen sollte es auch in Access geben....


Beste Grüße
Michael


Delete - Mi 13.05.09 10:26

Das sollte aber bei parametrisierten Abfragen im Normalfall gar nicht nötig sein.