Entwickler-Ecke

Datenbanken - Query: die besten der Klassen?


D. Annies - Di 30.06.09 13:48
Titel: Query: die besten der Klassen?
Hi, Delpher,
die folgende Query hat die Fehlermeldung:
Feld in order by muss im Resultat enthalten sein.


Delphi-Quelltext
1:
2:
3:
4:
query1.SQL.Text :=
      format('select S.geschlecht, max(S.punkte), S.klasse, S.name, S.vorname from "%s" S '  +
             'where (S.Punkte > 0) '+
             'order by S.geschlecht, S.punkte, S.Klasse, S.name, S.vorname', [Table2.tablename]);


Es soll der jeweils beste / die beste aus 6 verschiedenen Klassen angezeigt werden.

Danke für Hilfe,
Detlef


D. Annies - Di 30.06.09 14:12

Bin jetzt an der folgenden Stelle, aber immer noch fehlerhaft:
(Hab noch bisschen drumherum Code angezeigt)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
  query1.Close;
    query1.SQL.Text :=
      format('select geschlecht, max(punkte) as maxpkt, klasse, name, vorname from "%s" S '  +
             'group by geschlecht, Klasse, name, vorname', [Table2.tablename]);
  query1.Open;
  showmessage(inttostr(query1.RecordCount));

  query1.First;
  n := 1;
  repeat
    stringgrid1.Cells[0,n] := inttostr(n);
    stringgrid1.Cells[1,n] := query1.fieldbyname('maxPkt').asstring;
    stringgrid1.Cells[2,n] := query1.fieldbyname('Geschlecht').asstring;
    stringgrid1.Cells[3,n] := query1.fieldbyname('Klasse').asstring;
    stringgrid1.Cells[4,n] := query1.fieldbyname('Name').asstring;
    stringgrid1.Cells[5,n] := query1.fieldbyname('Vorname').asstring;
    query1.Next; inc(n);
  until n = query1.RecordCount+1;
  stringgrid1.RowCount := n;


Nersgatt - Di 30.06.09 14:16

Du verwendest eine Agregatfunktion (MAX). Dann musst Du die anderen Felder gruppieren (GROUP BY)


D. Annies - Di 30.06.09 19:56

Hi, Nersgatt,

aber ich denke, es ist gruppiert?
Kann nochmal jemand hingucken?
Detlef


dummzeuch - Di 30.06.09 20:20

user profile iconD. Annies hat folgendes geschrieben Zum zitierten Posting springen:

Feld in order by muss im Resultat enthalten sein.


Delphi-Quelltext
1:
2:
3:
4:
query1.SQL.Text :=
      format('select S.geschlecht, max(S.punkte), S.klasse, S.name, S.vorname from "%s" S '  +
             'where (S.Punkte > 0) '+
             'order by S.geschlecht, S.punkte, S.Klasse, S.name, S.vorname', [Table2.tablename]);


In Select sind enthalten:
* geschlecht
* klasse
* name
* vorname

In Order By sind enthalten:
* geschlecht
* punkte
* klasse
* name
* vorname

Was fehlt? Punkte

Das liegt daran, dass Du fuer Punkte eine Aggregatfunktion (Max) verwendest, ohne zu gruppieren.

Folgendes sollte funktionieren (ungetestet):


SQL-Anweisung
1:
2:
3:
4:
5:
select max(punkte) maxpunkte, geschlecht, klasse, name, vorname
from xxx
group by geschlecht, klasse, name, vorname
having maxpunkte > 0
order by maxpunkte


twm


D. Annies - Di 30.06.09 20:38

Funktioniert leider nicht!
Wer hat eine Idee?

Nochmal zur Sicherheit:
Es sind ca. 180 S in 6 Klassen. Die 6 besten Mä und die 6 besten Ju will ich sehen.
Also immer das beste Mä und den besten Ju pro Klasse, das sind also 12 Datensätze.

Danke, Detlef


jfheins - Mi 01.07.09 00:06

Ich hab da was :mrgreen:

Dank dir hab ich gelernt, wozu joins gut sind ^^

AAAlso: Meine Test-Tabelle:

SQL-Anweisung
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:
-- phpMyAdmin SQL Dump
-- version 3.3.0-dev
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Erstellungszeit: 01. Juli 2009 um 00:05
-- Server Version: 5.1.34
-- PHP-Version: 5.2.9-4

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

--
-- Datenbank: `test`
--

-- --------------------------------------------------------

--
-- Tabellenstruktur für Tabelle `meintest`
--

CREATE TABLE IF NOT EXISTS `meintest` (
  `id` int(11NOT NULL AUTO_INCREMENT,
  `klasse` int(11NOT NULL DEFAULT '0',
  `geschlecht` enum('m','w'NOT NULL DEFAULT 'm',
  `punkte` int(11NOT NULL DEFAULT '0',
  `name` varchar(255NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=13 ;

--
-- Daten für Tabelle `meintest`
--

INSERT INTO `meintest` (`id`, `klasse`, `geschlecht`, `punkte`, `name`) VALUES
(11'm'120'hans'),
(31'w'110'sophie'),
(41'm'104'klaus'),
(52'm'124'hansi'),
(62'w'30'lena'),
(72'w'106'claudia'),
(82'm'90'detlef'),
(92'w'87'annemarie'),
(103'm'80'hans 2'),
(113'm'107'Klaus 2'),
(123'w'96'Julia');


Und mein Statement:

SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
SELECT name, geschlecht, klasse, punkte
FROM (
SELECT max( punkte ) maxpunkte, geschlecht g, klasse k
FROM meintest
GROUP BY klasse, geschlecht
AS a
LEFT JOIN meintest ON maxpunkte = punkte
AND g = geschlecht
AND k = klasse

(benötigt MySQL 5.1 oder besser)

Ergebnis:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
name   geschlecht   klasse   punkte 
----------------------------------------
hans  m  1  120
sophie  w  1  110
hansi  m  2  124
claudia  w  2  106
Klaus 2  m  3  107
Julia  w  3  96


:D

Achja: Ich weis nicht obs einfacher geht, aber ganz trivial dürfte es nicht sein.


D. Annies - Mi 01.07.09 07:59

Moin, jfheins,

um die Uhrzeit noch fit: alle Achtung!
Aber ich muss noch basteln, noch bekomme ich die Fehlermeldung:

Ungültiges Schlüsselwort Symbolstring SELECT Zeilennummer 1

und das bei folgendem "Stand":


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
format('SELECT name, vorname, geschlecht, klasse, punkte ' +
             'FROM (SELECT max(punkte) as maxpunkte, geschlecht g, klasse k ' +
                   'FROM "%s" S ' +
                   'GROUP BY klasse, geschlecht) AS a ' +
             'LEFT JOIN S ON maxpunkte = punkte ' +
                         'AND g = geschlecht ' +
                         'AND k = klasse ', [Table2.tablename]);


Wird wohl bald gelöst sein ... :think:

bis denn, fahr jetzt erstmal zur Schule ...
Gruß, Detlef


Nersgatt - Mi 01.07.09 08:03

Welches Datenbanksystem benutzt Du? Subselects werden nicht von allen Systemen untersützt.


D. Annies - Mi 01.07.09 09:18

Hi, Nersgatt,

nun, ich nehme den SQL-Dialekt von Delphi 6.

Gibt es dafür eine Lösung?


jasocul - Mi 01.07.09 09:37

Delphi hat mit dem SQL-Dialekt nichts zu tun.
Führe den Befehl mal direkt auf der Datenbank aus. Es gibt bestimmt ein Front-End dafür.


D. Annies - Mi 01.07.09 09:40

Hi, Peter,

leider weiß ich nicht, wie das geht, aber deine zweite Aussage läßt mich ja doch hoffen.

Gruß, Detlef


jasocul - Mi 01.07.09 09:42

Welches DB-System verwendest du?
Wenn du das sagen kannst, können wir dir vermutlich auch ein kostenloses Front-End empfehlen.


D. Annies - Mi 01.07.09 09:56

Hi, Peter,

ich verwende D6 Enterprise, mit den mitgelieferten Komponenten. BDE?

Detlef


jasocul - Mi 01.07.09 10:05

Hallo Detlef,

BDE? :shock: Demnach verwendest du vermutlich Paradox. Ist zumindest die Standard-Einstellung.
Die BDE könnte dir tatsächlich in die Suppe spucken. Aber ich meine, dass bei den BDE-Versionen von Delphi ein DB-Explorer dabei war, mit dem man auch SQL-Anweisungen "direkt" machen kann. Allerdings weiß ich nicht, wo dieser Explorer versteckt ist. Das ist leider schon ziemlich lange her, dass ich das verwendet habe.

Gruß Peter


D. Annies - Mi 01.07.09 13:50

Hi, Peter, ja stimmt, es gibt einen DBExplorer.

Aber es wäre schade, wenn ich auf diese Auswertung per Query verzichten müsste; dann müsste ich wohl etwas programmieren.

Gruß, Detlef


Nersgatt - Mi 01.07.09 14:09

Wie wäre es denn damit (getestet mit FB 2.0):

SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
select name, punkte, geschlecht, klasse
from
    meintest mt
where punkte = (select
                    max(punkte)
                from meintest mt2
                where
                    mt2.klasse = mt.klasse and
                    mt2.geschlecht = mt.geschlecht
                group by klasse, geschlecht)

Selbe Testtabelle, wie von jfheins.


BenBE - Mi 01.07.09 14:32

Hier mal ohne Sub-Selects:

SQL-Anweisung
1:
2:
3:
4:
5:
SELECT t.klasse, t.geschlecht, t.name, t.punkte
FROM meintest AS t INNER JOIN meintest AS t2 ON t.id = t2.id
WHERE t.punkte = MAX(t2.punkte)
GROUP BY t2.klasse, t2.geschlecht
ORDER BY t.klasse, t.geschlecht


Ungetestet, sollte aber soweit tun ...


Nersgatt - Mi 01.07.09 14:52

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Ungetestet, sollte aber soweit tun ...

Sollte soweit NICHT tun. Aggregatfunktion in der Where-Klausel, da muss man HAVING benutzen.


D. Annies - Mi 01.07.09 15:19

Danke erstmal wieder, ich möchte den Tabellennamen gern variabel übergeben, aber noch Fehler zur Laufzeit: prg schmiert ab --> Taskmanager

aktuelle Version:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
      format('select name, punkte, geschlecht, klasse ' +
             'from "%s" S ' +
             'where punkte = (select ' +
                               'max(punkte) ' +
                               'from "%s" F ' +
                               'where F.klasse = S.klasse and ' +
                               '  F.geschlecht = S.geschlecht ' +
             'group by klasse, geschlecht)', [table2.tablename, table2.tablename]);


Gruß, Detlef


D. Annies - Mi 01.07.09 15:48

Jetziger Stand:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
      format('select S.name, S.punkte, S.geschlecht, S.klasse ' +
             'from "%s" S ', [table2.tablename]) +
      format('where punkte = (select max(punkte) ' +
             'from "%s" F ', [table2.tablename]) +
             'where F.klasse = S.klasse and ' +
             '  F.geschlecht = S.geschlecht ' +
             'group by S.klasse, S.geschlecht)';


Meldung: Operation nicht anwendbar.
Detlef (ich sitze hier bei 34,7°C, echt)


D. Annies - Mi 01.07.09 17:04

@benny: Fehlermeldung: Merkmal nicht verfügbar. Ich habe so adaptiert:


Delphi-Quelltext
1:
2:
3:
4:
5:
format('SELECT s.klasse, s.geschlecht, s.name, s.vorname, s.punkte ' +
             'FROM "%s" S INNER JOIN "%s" T ON (s.name = t.name) and (s.vorname = t.vorname) and (s.klasse = t.klasse) ' +
             'WHERE s.punkte = MAX(t.punkte) ' +
             'GROUP BY s.klasse, s.geschlecht ' +
             'ORDER BY s.klasse, s.geschlecht', [table2.tablename, table2.tablename]);


Detlef


D. Annies - Mi 01.07.09 21:53

@ Peter:

Kann ich denn ein anderes FrontEnd einbinden und wenn ja, welches?

Gruß, Detlef [aufgeben is nich ] :D


Robert.Wachtel - Mi 01.07.09 22:08

Dein Frontend ist nicht das Problem, das Backend ist es.

Nimm ein vernünftiges RDBMS oder vergiss die ganzen intelligenten SQL-Konstrukte - das kann Paradox nicht.


D. Annies - Mi 01.07.09 22:14

Schade, schade!
Frage beantwortet?

Schnief, Detlef