PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit MySQL und verschachtelter Select-Abfrage


Eazy
2004-01-06, 00:16:22
Hi,

hab mal ne Frage: Ich schreibe gerade in Java ein Programm, mit dem ich auf eine MySQL Datenbank zugreifen muss. Die Verbindung klappt auch ganz gut, nur eine Anweisung kriege ich einfach nicht hin.

Und zwar will ich eigentlich nur den Datensatz mit dem kleinsten Datum aus der DB rauslesen. Dazu habe ich mal folgende Anweisung geschrieben:

SELECT * FROM tblwettbewerb WHERE Datum <= (SELECT MIN(Datum) FROM tblwettbewerb)

Nur bekomme ich von MySQL dann die Meldung, dass die Sytax nicht korrekt wäre. Die Anweisungen einzeln ausgeführt funktionieren aber. Nach einigem recherchieren habe ich jetzt herausgefunden, dass MySQL keine verschachtelten Selectabfragen unterstützt (jetzt weiss ich, warum unser Prof MySQL als Kinder-DBMS bezeichnet hat ;-)

Kennt da jemand ne Lösung für? Gibt es eventuell einen ganz einfachen Weg, den Datensatz mit einem kleinsten Wert zu bekommen? (Eventuell einen speziellen SQL oder MySQL SQL Befehl?)

Gruß
Eazy

P.S. falls es jemand interessiert, der Code außenrum sieht so aus:

String url = "jdbc:mysql://"+hostname+":"+port+"/"+dbname;
conn = DriverManager.getConnection(url, user, password);

Statement stmt = conn.createStatement();

System.out.println("// Abfrage beginnen");

String sqlCommand = "SELECT * FROM tblwettbewerb WHERE Datum <= (SELECT MIN(Datum) FROM tblwettbewerb)";
ResultSet rs = stmt.executeQuery(sqlCommand);

System.out.println("// Ergebnisse anzeigen");
while (rs.next()) {

String resultDatum = rs.getString("Datum");

System.out.println( resultDatum );
}

stmt.close();

conn.close();

ethrandil
2004-01-06, 01:02:51
vielleicht so:

SELECT * FROM tblwettbewerb HAVING Datum = MIN(Datum);

oder so:

SELECT *, MIN(Datum) AS maxdat FROM tblwettbewerb HAVING Datum = maxdat;

?

Aqualon
2004-01-06, 01:55:02
Du könntest es auch folgendermaßen machen:


SELECT * FROM tblwettbewerb order by Datum asc limit 1


Wobei ich nicht weiß, was du mit kleinstem Datum meinst. Bei asc wird das älteste Datum geliefert, bei desc das jüngste Datum.

Subqueries gehen bei MySQL erst ab Version 4.1

Infos, wie man Subqueries umschreiben kann, dass sie auch mit älteren Versionen gibt es unter http://www.mysql.com/doc/en/Rewriting_subqueries.html

Aqua

Eazy
2004-01-06, 12:59:09
Original geschrieben von Aqualon
Du könntest es auch folgendermaßen machen:


SELECT * FROM tblwettbewerb order by Datum asc limit 1


Wobei ich nicht weiß, was du mit kleinstem Datum meinst. Bei asc wird das älteste Datum geliefert, bei desc das jüngste Datum.

Subqueries gehen bei MySQL erst ab Version 4.1

Infos, wie man Subqueries umschreiben kann, dass sie auch mit älteren Versionen gibt es unter http://www.mysql.com/doc/en/Rewriting_subqueries.html

Aqua

Thx, so geht dat :up:
(Ich meinte übrigens das jüngste Datum, wieder was gelernt ;-)

So ziemlich genau nachdem wir mit MySQL angefangen haben kam die Version 4.1 mit Subqueries raus (benutze gerade 4.0.16). 4.1 Scheint aber noch eine Alpha Version zu sein (mal überlegen ob wir noch umsteigen sollen).

@ ethrandil

Komischerweise kann ich auf Deine 1. Art zwar das älteste Datum rausfinden, jedoch nicht das jüngste. Die untere Abfrage hat bei mir nicht funktioniert.

So bekomme ich das älteste Datum: SELECT * FROM tblwettbewerb HAVING Datum > MIN(Datum);

Aber damit bekomme ich nicht das jüngste Datum (Leeres Ergebnis): SELECT * FROM tblwettbewerb HAVING Datum <= MIN(Datum); :kratz:

Danke nochmal,

Gruß
Eazy

Lokadamus
2004-01-06, 13:16:03
mmm...

Ganz blöd geraten:
Aber damit bekomme ich nicht das jüngste Datum (Leeres Ergebnis): SELECT * FROM tblwettbewerb HAVING Datum <= MIN(Datum);Du versuchst gerade, einen Wert zu finden, der kleiner ist als der Ausgangswert ;) ... wenn es ein Min gibt, sollte es auch ein Max oder ähnliches geben, vielleicht geht:

SELECT * FROM tblwettbewerb HAVING Datum <= Max(Datum) ... kann es nicht testen, hab nix da zum Proggen ...

Wegen: SELECT * FROM tblwettbewerb order by Datum asc limit 1
Da hat Auqualon doch schon geschrieben:
SELECT * FROM tblwettbewerb order by Datum desc limit 1
lässt dich nach dem jüngsten Datum suchen, sollte eigentlich gehen ...

Eazy
2004-01-06, 14:15:30
Original geschrieben von Lokadamus
mmm...

Ganz blöd geraten:
Du versuchst gerade, einen Wert zu finden, der kleiner ist als der Ausgangswert ;) ... wenn es ein Min gibt, sollte es auch ein Max oder ähnliches geben, vielleicht geht:

SELECT * FROM tblwettbewerb HAVING Datum <= Max(Datum) ... kann es nicht testen, hab nix da zum Proggen ...

Wegen: SELECT * FROM tblwettbewerb order by Datum asc limit 1
Da hat Auqualon doch schon geschrieben:
SELECT * FROM tblwettbewerb order by Datum desc limit 1
lässt dich nach dem jüngsten Datum suchen, sollte eigentlich gehen ...

Irgendwie war ich gerade voll verwirrt. Hatte sogar die falsche SELECT Abfrage in mein Programm geschrieben.

Jetzt ist es mir aber klar. Ich wollte also das jüngste Datum (hatte aber das älteste implementiert). "SELECT * FROM tblwettbewerb order by Datum desc limit 1" ist dann richtig. THX.





Um mich jetzt wieder zu verwirren: Eigentlich müsste "SELECT * FROM tblwettbewerb HAVING Datum = MAX(Datum);" wie Du es oben geschrieben hast doch auch gehen. Geht aber net?

Also "SELECT MAX(Datum) from tblwettbewerb" gibt mir das jüngste Datum, das habe ich ausprobiert. Sehr seltsam. Aber was solls, hauptsache es geht.

Entweder mache ich es jetzt so wie oben, oder ich schau mir mal die Version 4.1 an. Subqueries braucht man doch eigentlich recht oft und so Tricks wie Ihr kenne ich leider net. (Will Euch ja nicht dauernd mit meinen Fragen belästigen ;-)

Danke und Gruß
Eazy

HellHorse
2004-01-06, 19:24:45
Kleiner Tipp am Rande:
Connection's nicht über den DriverManager, sondern über eine DataSource erzeugen:

DataSource dataSource = ....;
Connection connection = dataSource.getConnection();

Erzeugen einer MySQLDataSource:

public static DataSource getMySQLDataSource(String host, int port, String db,String user, String password) {
MysqlDataSource source = new MysqlDataSource();
source.setServerName(host);
source.setPortNumber(port);
source.setDatabaseName(db);
source.setUser(user);
source.setPassword(password);
return source;
}


Warum?
http://java.sun.com/j2se/1.4.2/docs/api/javax/sql/DataSource.html

public interface DataSource

A factory for connections to the physical data source that this DataSource object represents. An alternative to the DriverManager facility, a DataSource object is the preferred means of getting a connection. An object that implements the DataSource interface will typically be registered with a naming service based on the JavaTM Naming and Directory (JNDI) API

Zarathustra
2004-09-20, 11:03:29
Ich habe keine Klasse für "MySqlDatasource".
Wo kriegt man die her?

Zarathustra
2004-09-26, 12:18:29
Zum connecten zu einer MySQL-Datenbank komme ich nun also um den unten aufgeführten Mysql-Connector nicht herum...
Aber ich kann in nicht benutzen, obwohl ich die enthaltene
jar-Datei in den EXT-Ordner kopiert habe.
Konkret:
C:\Programme\s1studio_jdk\j2sdk1.4.1\jre\lib\ext wo sich nun die mysql-connector-java-3.0.15-ga-bin.jar befindet.

Nun ja die zip enthält ausser der .jar auch noch andere Dateien, aber soweit ich glaube das verstanden zu haben, brauche ich entweder die oder die .jar...

Trotzdem klappt nichts!?

Das Package stammt von hier: http://dev.mysql.com/downloads/connector/j/3.0.html

Was mach ich falsch?
Sorry bin wohl zu blöd dazu ;(

HellHorse
2004-09-26, 19:31:37
Nun ja die zip enthält ausser der .jar auch noch andere Dateien, aber soweit ich glaube das verstanden zu haben, brauche ich entweder die oder die .jar...
Eigentlich nur die mysql-connector-java-xxx-bin.jar


Was mach ich falsch?
Sorry bin wohl zu blöd dazu ;(
Was geht nicht? Compilieren oder ausführen?
Es sieht für mich so aus, als würdest du Sun ONE Studio verwenden.
Ich würde da eher die Funktionalität dieser IDE verwenden um libraries dem aktuellen Projekt hinzuzufügen. Wie das genau bei Sun ONE Studio kann ich dir nicht sagen, das Ding hat aber sicher eine Hilfefunktion.

Zarathustra
2004-09-27, 12:08:42
Das Ausführen ging nicht.


try
{
//jdbc.drivers = org.gjt.mm.mysql.Driver;
System.setProperty("jdbc.drivers", "org.gjt.mm.mysql.Driver");
String url = "jdbc:mysql://" + hostname + ":" + port + "/" + dbname;
conn = DriverManager.getConnection(url, username, password);
System.out.println("/n Connection created.");
Statement stmt = conn.createStatement();
System.out.println("/n Statement created.");
}
catch(SQLException ex)
{
while(ex != null)
{
ex.printStackTrace();
ex = ex.getNextException();
}
}

System.out.println("/n Will start Tool GUI now...");
ToolGUI tool = new ToolGUI(conn, stmt); *MARKIER*

System.out.println("/n ... Tool GUI Started.");
gui.connectButton.setLabel("Trennen");


Die Verbindung funktioniert jetzt. Danke für die Hinweise, ich hab die Treiberinformationen aus dem JDBC Form Wizard geholt, da war ein Mysql-Treiber anwählbar. :)

Aber dort wo im Code oben die Markierung ist, bricht die Ausführung immernoch ab! Kann es sein dass man Connection und/oder Statement aus irgendeinem Grund nicht per Konstruktor übergeben darf?

EDIT:
Dir fällt sicher auf, dass ich keine MysqlDataSource verwende, wie oben empfohlen. Das liegt daran, dass ich noch keinen Weg gefunden habe, die erforderlichen Klassen einzubinden. Die Hilfe handelt nur von der Erzeugung von jar Files. Der Import Manager der IDE schmiert sofort ab, wenns interessant wird, dabei handelt es sich um Forte 4 Community Edition. Ich hatte erst SUN ONE drauf, hab aber gewechselt weil das abstürtzte, wenn man eine eigene GUI beendete. Dummerweise ist das bei dem Forte hier dasselbe... :mad:

Ich habs nochmal versucht ohne das Statement zu übergeben (kann ich ja dann dort immernoch erzeugen), gleiches Ergebnis.
Der erste Fehler in der ausgeworfenen Liste lautet: java.lang.NullPointerException, wenn das hilft. :|

HellHorse
2004-09-27, 22:38:57
while(ex != null)
{
...
ex = ex.getNextException();
}

Hast du das irgendwoher? Nötig ist das eigentlich nicht (das while). Ein einfaches ex.printStackTrance() sollte ausreichen.

Aber dort wo im Code oben die Markierung ist, bricht die Ausführung immernoch ab!

Geht's etwas genauer? Was für eine Exception, Stacktrace (idealerweise mit Zeilennummer) , ...
Für mich sieht es so aus, als wäre das Problem irgendwo im ToolGUI Konstruktor. Ist das eine eigene Klasse, oder hast du die irgendwoher?

Kann es sein dass man Connection und/oder Statement aus irgendeinem Grund nicht per Konstruktor übergeben darf?
Höchstens Stilgründe und zwar DB und GUI Code nicht zu mixen. *Zaunpfahl*

Ich habs nochmal versucht ohne das Statement zu übergeben (kann ich ja dann dort immernoch erzeugen), gleiches Ergebnis.
Der erste Fehler in der ausgeworfenen Liste lautet: java.lang.NullPointerException, wenn das hilft. :|
Du hast null übergeben und wunderst dich, warum du eine NullPointerException kriegst?

Zarathustra
2004-09-27, 23:00:54
Du hast null übergeben und wunderst dich, warum du eine NullPointerException kriegst?

Nee! Dazu hab ich dann natürlich auch den Konstruktor zeitweise geändert, sodass nur noch die Connection "conn" übergeben wurde.


Das ist die momentane ToolGUI-Klasse, das hier ist alles von mir:

import bla...bla;

public class ToolGUI
{
String[] tables = new String[] {"Table1dummy", "Table2dummy"};
public ToolFrame gui;
private Connection conn;
//private Statement stmt;

public ToolGUI(Connection conn)//, Statement stmt)
{
this.conn = conn;
//this.stmt = stmt;

gui = new ToolFrame("Titel", tables);

//Listener
...
}
}
Und hier drin wollte ich eine Referenz auf die Connection haben, sodass hier auch die SQL-Statements je nach Listener ausgeabrbeitet werden können.

Zur Information noch die ToolFrame-Klasse:

public class ToolFrame extends JFrame
{
//Hier folgt die Erstellung der Fensterkomponenten

public ToolFrame(String title, String[] tables)
{
super(title);
this.tables = tables;
setDefaultCloseOperation(EXIT_ON_CLOSE);

gbl = new GridBagLayout();
getContentPane().setLayout(gbl);

/*Jetzt wird hier zusammengebaut mit einer eigenen Methode, für die "gbl" von oben nötig ist, falls du dich wunderst. Ich führ sie mal ganz unten mit auf.*/

setSize(640,480);

setVisible( true );
}

static void addComponent(JFrame cont, GridBagLayout gbl, Component c,
int x, int y,
int width, int heigt,
double weightx, double weighty )
{
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = gbc.BOTH;
gbc.gridx = x; gbc.gridy = y;
gbc.gridwidth = width; gbc.gridheight = heigt;
gbc.weightx = weightx; gbc.weighty = weighty;
gbl.setConstraints( c, gbc );
cont.getContentPane().add( c );
}
}
Hier bin ich mir mit dem setVisible unten nicht ganz sicher. Das hat aber beim Testen der einzelnen ToolGUI am Anfang funktioniert. Mich irritieren aber die Alternativen die dazu noch zu finden sind: pack() und show(), aber das scheint hier keinen Unterschied zu machen.

Zarathustra
2004-09-27, 23:39:39
Hier die komplette Fehlermeldung beim Fehlschlagen des ToolGUI-Aufbaus.
Ich hab die Zeilen aus meinem Code reingeschrieben.

host: localhost
port: 3306
dbname: clm_board
username: root
password:
Connection created.
Will start Tool GUI now...
java.lang.NullPointerException
at javax.swing.JList$1.getSize(JList.java:319)
at javax.swing.JList.getPreferredScrollableViewportSize(JList.java:1909)
at javax.swing.ViewportLayout.preferredLayoutSize(ViewportLayout.java:72)
at java.awt.Container.preferredSize(Container.java:1175)
at java.awt.Container.getPreferredSize(Container.java:1159)
at javax.swing.JComponent.getPreferredSize(JComponent.java:1274)
at javax.swing.ScrollPaneLayout.preferredLayoutSize(ScrollPaneLayout.java:475)
at java.awt.Container.preferredSize(Container.java:1175)
at java.awt.Container.getPreferredSize(Container.java:1159)
at javax.swing.JComponent.getPreferredSize(JComponent.java:1274)
at java.awt.GridBagLayout.GetLayoutInfo(GridBagLayout.java:892)
at java.awt.GridBagLayout.getLayoutInfo(GridBagLayout.java:806)
at java.awt.GridBagLayout.ArrangeGrid(GridBagLayout.java:1373)
at java.awt.GridBagLayout.arrangeGrid(GridBagLayout.java:1336)
at java.awt.GridBagLayout.layoutContainer(GridBagLayout.java:706)
at java.awt.Container.layout(Container.java:1017)
at java.awt.Container.doLayout(Container.java:1007)
at java.awt.Container.validateTree(Container.java:1089)
at java.awt.Container.validateTree(Container.java:1096)
at java.awt.Container.validateTree(Container.java:1096)
at java.awt.Container.validateTree(Container.java:1096)
at java.awt.Container.validate(Container.java:1064)
at java.awt.Window.show(Window.java:450)
at java.awt.Component.show(Component.java:1134)
at java.awt.Component.setVisible(Component.java:1089)
at ToolFrame.<init>(ToolFrame.java:97)
lautet: "setVisible( true );"
at ToolGUI.<init>(ToolGUI.java:24)
lautet: "gui = new ToolFrame("Titel", tables);"
at ConnectorGUI$2.actionPerformed(ConnectorGUI.java:89)
lautet: "ToolGUI tool = new ToolGUI(conn);//, stmt);"
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1764)
at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.ja va:1817)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:419)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:257)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.jav a:245)
at java.awt.Component.processMouseEvent(Component.java:5093)
at java.awt.Component.processEvent(Component.java:4890)
at java.awt.Container.processEvent(Container.java:1566)
at java.awt.Component.dispatchEventImpl(Component.java:3598)
at java.awt.Container.dispatchEventImpl(Container.java:1623)
at java.awt.Component.dispatchEvent(Component.java:3439)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3450)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3165)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3095)
at java.awt.Container.dispatchEventImpl(Container.java:1609)
at java.awt.Window.dispatchEventImpl(Window.java:1585)
at java.awt.Component.dispatchEvent(Component.java:3439)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:450)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:1 97)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150 )
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:144)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:136)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)

Das mit dem setVisible() macht mich fertig, aber pack() nd show() klappen auch nicht. X-(

Danke für deine Zeit!

HellHorse
2004-09-28, 01:27:06
pack() und show(), aber das scheint hier keinen Unterschied zu machen.
show() sollte setVisible(true) aufrufen, ist/wird aber mit 1.5 deprecated, also Finger weg.
Sehe ich das richtig, wenn du weder pack() noch show() noch setVisible(true) machst, kommt keine Exception (und keine Anzeige)?


java.lang.NullPointerException
at javax.swing.JList$1.getSize(JList.java:319)
at javax.swing.JList.getPreferredScrollableViewportSize(JList.java:1909)
...


Wow, ein NullPointer in ein einer annonymen inneren Klasse von JList.
Zudem stimmen bei meinen Sourcen die Zeilennummern mit deinen nicht überein.
Wonach es für mich aussieht:
Du rufst entweder den JList Konstruktor mit einem Array oder Vector oder setListData an einer JList auf. Der Parameter ist null. Irgendwann später beisst es dich dann.
Wenn ich raten müsste:
Den JList Konsturkor mit einem Array.

K.A. warum die Swing Leute das Argument bei einem ListModel auf null checken aber bei einem Array oder Vector nicht.
Aber da gäbs noch ein paar andere Fragen, die ich denen gerne stellen würde.

Zarathustra
2004-09-28, 11:42:13
Tatsächlich! :biggrin:

Ich hatte in ToolFrame die JList mit einem (vorerst) leeren Array erstellen wollen!
Tz... Dabei ist es so einfach.

Ich hab jetzt
protected JList tableList;
und
tableList = new JList(tables);
getrennt und letzteres in den Konstruktor verfrachtet.
Nun gehts erstmal soweit.

Vielen Dank für deine Hilfe! :up: