ResultSet-Ergebnis mit INSERT in Tabelle schreiben

Hallo Gemeinde,
ich möchte mit einem Java-Programm ein mit ResultSet erzeugtes Ergebnis aus einer Tabelle in eine andere Tabelle schreiben.
Hier mein Java-Code:

public static void Abfrage()
{
try
{
stmt = con.createStatement();
String abfragen = "SELECT * FROM auftragsplanung ";
ResultSet rs = stmt.executeQuery(abfragen); //Abfrage aus Tabelle auftragsplanung

/* daten durchlaufen */
while (rs.next())
{
String Folie = rs.getString(9); //Spalte (9) ist Deckelfolie!
Integer Verbrauch = rs.getInt(4); //Spalte (4) ist Stückzahl!
System.out.print(Folie); System.out.println(" “+Verbrauch);
//Abgefragte Werte einsetzen in Tabelle tab1
String einsetzen = “INSERT INTO tab1 (folie,verbrauch)
VALUES(”+Folie+”,"+Verbrauch+")";
stmt.executeUpdate(einsetzen);
}
}
catch (Exception e)
{
System.out.println("PG-Fehler: " + e.getMessage());
}
}
Als Fehlermeldung von postgres bekomme ich das:

ec@linux:~/Postgres/Daten> java testfolie
Verbunden mit: jdbc :p ostgresql://localhost/Auftrag/
hs1250x0,135 121
PG-Fehler: FEHLER: Spalte »hs1250x0« existiert nicht
Tabelle ist geschlossen
ec@linux:~/Postgres/Daten>

Die erste Zeile des ResultSets wird durch die Print-Befehle noch angezeigt. Dann entsteht offenbar beim Zugriff auf die Tabelle tab1 ein
Fehler, der dann geworfen wird.
Was ist an dieser Konstruktion faul und wie muß es richtig heißen?
Schon mal vielen Dank für Eure Mitarbeit,
Gruß Scheff

Da sind mehrere Fehler. Zum einen, ein SELECT * ist böse. Zum anderen, auf einzelne Spalten via der (vermuteten) Nummer zuzugreifen. Beides fällt Dir schmerzhaft auf die Füße, wenn sich die Tabellenstruktur mal ändert.

Der eigentliche Fehler dürfte aber " statt ’ bei VALUES("+Folie+","+Verbrauch+")"; sein.

Im übrigen: Deine Methode, so durch ein Resultat zu latschen und Record für Record vom Server auf den Client zu zerren, um ihn dann wieder woanders einfügen zu können, ist eine schlechte Idee: Du kannst das auch direkt via insert … select machen. Das geht um etliche zehnerpotenzen dann schneller.


Andreas

Hallo Andreas, vielen Dank für die prompte Antwort.
Dein Tip mit den einfachen Apostrophen anstatt den doppelten hat nichts gebracht. Der
Compiler macht dann natürlich aus meiner int-Variablen eine Text-Variable, die er an dieser Stelle natürlich nicht in die Tabelle einfügen kann.
Nochmal der abgeänderte Code:

public static void Abfrage()
{
try
{
stmt = con.createStatement();
String abfragen = "SELECT * FROM auftragsplanung ";
ResultSet rs = stmt.executeQuery(abfragen); //Abfrage aus Tabelle auftragsplanung

/* daten durchlaufen */
while (rs.next())
{
String Folie = rs.getString(9); //Spalte (9) ist Deckelfolie!
Integer Verbrauch = rs.getInt(4); //Spalte (4) ist Stückzahl!
System.out.print(Folie); System.out.println(" “+Verbrauch);
//Abgefragte Werte einsetzen in Tabelle tab1
//String einsetzen = “INSERT INTO tab1 (folie,verbrauch) VALUES(”+Folie+”,"+Verbrauch+")";
String einsetzen = “INSERT INTO tab1 (folie,verbrauch) VALUES(’+Folie+’,’+Verbrauch+’)”;
stmt.executeUpdate(einsetzen);
}
}
catch (Exception e)
{
System.out.println("PG-Fehler: " + e.getMessage());
}
}
Mit zugehöriger Fehlermeldung:

ec@linux:~/Postgres/Daten> java testfolie

Verbunden mit: jdbc :p ostgresql://localhost/Auftrag/

hs1250x0,135 121
PG-Fehler: FEHLER: ungültige Eingabesyntax für ganze Zahl: »+Verbrauch+«
Tabelle ist geschlossen

Das Programm werde ich später noch optimieren, aber in dieser Testphase will ich erst mal die INSERT-Konstruktion zum Laufen bringen.
Zum besseren Verständnis vielleicht noch die Struktur der beiben Tabellen:
Auftrag=# \d auftragsplanung
Tabelle »public.auftragsplanung«
Spalte | Typ | Attribute
--------------±-----------------------±------------------------------------------------------------------------
Auftrags-ID | integer | not null default nextval(’“Auftragsplanung_Auftrags-ID_seq”’::regclass)
Auftrags-Nr | character varying(255) |
Kunde | character varying(255) |
Stückzahl | bigint |
Termin | character varying(255) |
Abmessung | character varying(255) |
Haubenlänge | bigint |
Haubenbreite | bigint |
Deckelfolie | character varying(255) |
Umfangsfolie | character varying(255) |
Foliendicke | real |
Bemerkung | character varying(255) |
Indexe:
»Auftragsplanung_pkey« PRIMARY KEY, btree (“Auftrags-ID”)


Auftrag=# \d tab1
Tabelle »public.tab1«
Spalte | Typ | Attribute
-----------±------------------±----------
folie | character varying |
verbrauch | integer |

Auftrag=#

Ich will daraus die Spalten Deckelfolie, Stückzahl respektive Umfangsfolie, Stückzahl
in den beiden Spalten folie, verbrauch untereinander schreiben, weil ich daraus später für eine Lagerliste die verbrauchten Folienmengen berechnen will.

Gruß Scheff

Die " sind in diesem Fall Java-Quotes für Java Strings … also der String sieht dann so aus :

" … VALUES("+Folie+", “+Verbrauch+”)";

Schwarz sind die Variablen die er vorher gefüllt hat … Also die vorherige Variante war schon beinahe OK - wenn man annimmt, dass Folie ein String und Verbrauch Integer ist müsste es so richtig sein.

" … VALUES("+Folie+", “+Verbrauch+”)";


Der besagte Fehler

PG-Fehler: FEHLER: ungültige Eingabesyntax für ganze Zahl: »+Verbrauch+«

kann viele Ursachen haben … dazu wäre es gut, wenn du (Scheff) mal den Stacktrace der PLSQLException schicken wuerdest.

Sind Trigger auf den Tabellen deren Funktionen den Fehler verursachen koennten?

Gruß
Steffen

Danke für die Richtigstellung.

Andreas

Hallo symbiont und Andreas,
IHR SEID SPITZE !! :slight_smile: Klasse Zusammenarbeit :slight_smile:
Das war wieder ein Volltreffer! :slight_smile:
Eine String-Variable muß man mit dieser Syntax ’ " + x + " ’ usw. übergeben. Das Programm schreibt allerdings nur den ersten Datensatz und schließt dann die Tabelle. Das liegt aber wohl nur an meiner unvorteilhaften Konstruktion. Wie Andreas schon angemerkt hat sollte man das so nicht machen.
Ich versuche jetzt den Stacktrace hinzubekommen (weiß noch nicht wie man das macht), werde den Code verbessern und melde mich dann wieder.
P.S. Kennt Ihr das Datenbank-Frontend “knoda”. Damit will ich mein Auftragsprogramm aufbauen.
Vielen Dank Scheff



try {

... mein Fehlerhafter Code :) .. 

} catch (SQLException e) {

   // Stacktrace auf der Console ausgeben .. 
   e.printStackTrace();
}

den kannst du dann aus der Console kopieren und hier posten

Hallo symbiont,
hier der Stacktrace:
ec@localhost:~/Postgres/Daten> java testfolie
Verbunden mit: jdbc :p ostgresql://localhost/Auftrag/
hs1250x0,135 121
PG-Fehler: Dieses ResultSet ist geschlossen.
org.postgresql.util.PSQLException: Dieses ResultSet ist geschlossen.
at org.postgresql.jdbc2.AbstractJdbc2ResultSet.checkClosed(AbstractJdbc2ResultSet.java:2585)
at org.postgresql.jdbc2.AbstractJdbc2ResultSet.next(AbstractJdbc2ResultSet.java:1803)
at testfolie.Abfrage(testfolie.java:73)
at testfolie.main(testfolie.java:22)

damit kann ich nun gar nix anfangen! :confused:
Es ist wohl so wie Andreas schon bemerkt hat. Der Code ist so nicht gut.
Wäre ein PreparedStatement die Lösung?

Hier noch der eingefügte Datensatz in der Tabelle:

Auftrag=# select * from tab1;
folie | verbrauch
--------------±----------
hs1250x0,135 | 121
(1 Zeile)
und der Vollständigkeit halber der komplette Java-Code:

/**Datenbankprogramm  testfolie.java */

import java.sql.*;

public class testfolie
{
 static DatabaseMetaData dmd;
 static Statement        stmt;
 static Connection       con;
// static ResultSet        resu;

 public static void main(String[] args) 
 {
   Verbinden();
   Abfrage();
   schliessen();
 }

 public static void Einfügen()
 {
   try 
   {  stmt = con.createStatement();
      int Verbrauch = 1200;
      String Folie = "'df2000x0,135'";
      String einsetzen = "INSERT INTO tab1 (folie,verbrauch) VALUES("+Folie+","+Verbrauch+")";
      for (int i=1;i<=5;++i){

      stmt.executeUpdate(einsetzen); }

      System.out.println("Werte sind eingefügt");
   } 
   catch (Exception e)
   {
     System.out.println("Fehler: " + e.getMessage());
   }
 } 

 public static void Abfrage()
 {
   try
   {
     stmt = con.createStatement();
     String abfragen = "SELECT * FROM auftragsplanung ";
     ResultSet  rs = stmt.executeQuery(abfragen);  

     while   (rs.next())
     {
       String Folie = rs.getString(9);  //Spalte (9) ist Deckelfolie!
       Integer Verbrauch = rs.getInt(4);    //Spalte (4) ist Stückzahl!
       System.out.print(Folie);  System.out.println("  "+Verbrauch); 
       String einsetzen = "INSERT INTO tab1 (folie,verbrauch) VALUES('"+Folie+"',"+Verbrauch+")";
       stmt.executeUpdate(einsetzen);
     }
   }
   catch (Exception e)
   {
     System.out.println("PG-Fehler: " + e.getMessage());
      e.printStackTrace();
   }
 } 

 public static void Verbinden()
 {
   try 
   { 
     Class.forName("org.postgresql.Driver");
   } 
   catch (ClassNotFoundException e) 
   {
     System.err.println("Driver class not found");
     e.printStackTrace();
   }   con = null;
   try 
   { 
     con = (Connection) DriverManager.getConnection(
            "jdbc :p ostgresql://localhost/Auftrag/","ec","");
     if (con == null) 
     {
       System.out.println("Keine Verbindung");
       System.exit(1);
     }
     else
     {
       System.out.println(" ");
  /**Metadaten ausgeben */
       dmd = con.getMetaData();
       System.out.println("Verbunden mit: "+ dmd.getURL());
       System.out.println(" ");
     }
   }
   catch (SQLException e1) 
   {   }
 } 

 public static void schliessen()
 {
   try
   {
     stmt.close();
     con.close();
     System.out.println("Tabelle ist geschlossen");
   }
   catch (SQLException e) 
   {
     Throwable t = e;
     while (t != null) 
     {
       System.err.println("Type: " + t.getClass().getName());
       System.err.println("Message: " + t.getMessage());
       System.err.println("-----");
       t = t.getCause();
     } 
   }
 }
}

Gruß Scheff

wenn der Fehler beim Schreiben auftritt, mir scheint es jedoch, der Fehler tritt auf, weil Du das gleiche java.sql.Statement für Dein executeUpdate(…) verwendest, dass Du vorher zum Öffnen des ResultSet verwendet hast.

Das heisst, das (von Statement stmt abhängige) ResultSet wird bei dem executeUpdate(“INSERT …”) geschlossen so dass der Fehler bei rs.next(.) auftreten muss.


Was du eigentlich versucht hast, ist das updatefaehige Resultset zu nutzen … ich arbeite so selbst nicht … aber probiere mal folgenedes

statt dem executeUpdate(“INSERT …”) verwendest Du
rs.updateString(index , value) um die Feldwerte zu setzen … analog rs.updateInt(… ) etc. und commitest die Änderungen danach mit rs.updateRow().

das Statement selbst fasst Du dabei nimmer an - ausser wenn Du mit dem Rumaendern fertig bist - das ResultSet und Statement schliessen …

gruß

p.s. oder du erzeugst dir eine weitere Statement-Instanz für ein selbstgeneriertes INSERT incl Werten im String … oder ein PreparedStatement mit Parametern eben … zum “kennen-lernen” kann es nicht falsch sein, wenn du die nichtmal eine handvoll Möglichkeiten ausprobierst. Die paar Zeilen Code haben Dir ja bereits ein wenig Zeit gekostst - da kommts daraf nun auch nimmer an …

Es ist aber immer gut zu wissen, WARUM ein Fehler aufgetreten ist - auch wenn dir jemand eine funktionierende Variante vorbetet …

in der JavaDoc zu java.sql.ResultSet steht:

A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.

Dort findest du auch diverse Beispiele, wie ein update-fähiges Resultset zu erzeugen ist (bestimmte Parameter für Statement etc.) und vieles mehr.