SQL-Statement SQLException: '' is not a valid name.

nahum77

Mitglied
Hallo zusammen

Ich bin mit meinem Latein wirklich am Ende und brauch hier mal Unterstützung!

Worum gehts:
Ich versuch durch Java mit SQL-Preparestatement in eine Access (2003) Tabelle zu schreiben. Die Acces Tabelle wiederum ist mit einem MS Sharepoint (2003) verlinkt.

Hier das Preparestatement:
SQL:
UPDATE [ChangeCalendar: v_stefan]  SET `Change ID` = ?,`Departement` = ?,`Anfangszeit` = ?,`Endzeit` = ? WHERE `Change ID` = ? AND Departement = ?

Die Parameter für den ersten Datensatz werden wie folgt gesetzt:

Change ID: CRQ000000040605
Departement: I
Anfangszeit: 2025-05-31 00:00:00
Endzeit: 2025-07-24 00:00:00
Change ID: CRQ000000040605
Departement: I
Wenn ich das Statement ausführe (Connection steht und preparestatement wurde gesetzt)
Java:
int updateCount = mPSU.executeUpdate();
erhalte ich folgende Exception:
Java:
java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver] '' is not a valid name.  Make sure that it does not include invalid characters or pun
ctuation and that it is not too long.
        at sun.jdbc.odbc.JdbcOdbc.createSQLException(Unknown Source)
        at sun.jdbc.odbc.JdbcOdbc.standardError(Unknown Source)
        at sun.jdbc.odbc.JdbcOdbc.SQLExecute(Unknown Source)
        at sun.jdbc.odbc.JdbcOdbcPreparedStatement.execute(Unknown Source)
        at sun.jdbc.odbc.JdbcOdbcPreparedStatement.executeUpdate(Unknown Source)
        at synchronizer2.Sync.clearSPFlag(Sync.java:507)
        at synchronizer2.Sync.update(Sync.java:642)
        at synchronizer2.Sync.sync_change(Sync.java:209)
        at synchronizer2.Sync.<init>(Sync.java:130)
        at synchronizer2.MyTimer.work(MyTimer.java:114)
        at synchronizer2.MyTimer.access$000(MyTimer.java:24)
        at synchronizer2.MyTimer$1.run(MyTimer.java:65)
        at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
        at java.util.concurrent.FutureTask$Sync.innerRunAndReset(Unknown Source)
        at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

Ich habe schon beinahe jegliche Kombination und Möglichkeit probiert. Bei den Begrenzern mit ' oder ` oder " ist immer dasselbe oder der Treiber reklamiret wegen Syntaxe oder too few Paramter oder so. Auch den Tabellennamen mit " zu begrenzen hat nichts gebracht.

Bei den Dates für Anfangs- und Endzeit habe ich zunächst versucht mit Timestamp zu arbeiten aber Access (oder wahrscheinlich eher der Sharepoint) hat ein Prob mit den Millisekunden. Daher übergebe ich das Datum nun als String (bei INSERT hat das so funktioniert).

Bei Dr. Google liest mann dazu öfters was von Apostrophs oder anderen Sonderzeichen in Pfaden. Ich verwende aber keine Pfade oder ist der Pfad im ODBC zur DB gemeint oder allenfalls der Link der DB zum Sharepoint? Ich blick nicht mehr durch! ???:L

Aus dem ODBC-trace bin ich auch nicht schlau geworden. Jrgend wo steht dann:
Synchronizer2 142c-15b8 EXIT SQLExecute with return code -1 (SQL_ERROR)
HSTMT 031F3AA8

oder etwas weiter:
Synchronizer2 142c-15b8 EXIT SQLErrorW with return code 100 (SQL_NO_DATA_FOUND)
HENV 00000000
HDBC 00000000
HSTMT 031F3AA8
WCHAR * 0x031BF584 (NYI)
SDWORD * 0x031BF5CC
WCHAR * 0x031BF184
SWORD 300
SWORD * 0x031BF5C8
In der Tablle ist der Datensatz vorhanden und die Parameter stimmen auch überein.

Als Anhang noch der ODBC-Trace. Die Stellen wo es interessant zu werden scheint findet man am bestem mit suchen nach

Hoffe wirklich sehr, dass mir hier jemand helfen kann.
Herzlichen Dank schon mal im Voraus.

Grüsse
Nahum77
 

Anhänge

Herzlichen Dank für die schnelle Antwort.

Habe gleich dazu noch Fragen:

Access kann leider kein Prepare. Deshalb wird das so nicht funktionieren.

Das ist sicher so, aber ich hoffe bald auf einen MS SQL Server wechseln zu können und habe daher schon etwas voraus gedacht (oder versucht...)

Allerdings sollte das mit den Prepare auf Access laut API auch gehn da der Treiber damit umgehen können sollte:
Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement object is executed. This has no direct effect on users; however, it does affect which methods throw certain SQLException objects.

Bei einem INSERT hab ich das schon mal gemacht und da hat es geklappt (hat wahrscheinlich wirklich der Treiber für mich umgemüntzt).

Diese Zeichen solltest Du überhaupt weglassen, denn damit kann m.E. nur MySQL etwas anfangen und selbst da ist es läßtig.

Wie kann ich dann Spaltennamen mit Leerschlägen begrenzen? Ist natürlich auch unschön Spaltennamen mit Spaces zu führen, in dem Fall ist das aber ein Zugeständniss an den Sharepoint der den Spaltennamen 1:1 übernimmt und so darstellt. Ausserdem ist der Sharepoint nicht in meiner Verantwortung und ich kann da kaum Einfluss nehmen.

Nochmals Danke und Gruss
Nahum77
 
Freut mich, daß ich etwas beitragen konnte. 🙂

... Allerdings sollte das mit den Prepare auf Access laut API auch gehn da der Treiber damit umgehen können sollte: ... Bei einem INSERT hab ich das schon mal gemacht und da hat es geklappt (hat wahrscheinlich wirklich der Treiber für mich umgemüntzt).
Das ist eine Überraschung. Hättest Du bitte einen Link zu der Stelle in der API für mich.


... Wie kann ich dann Spaltennamen mit Leerschlägen begrenzen? ...
Den Spaltennamen mußt Du dafür in eckige Klammern setzten.
 
Hallo nochmals

Habe was gefunden bin mir aber nicht sicher ob ich auf dem richtigen Weg bin.
Irgendwo hat einer geschrieben, dass der Sharepoint nur updates akzeptiert die auf die ID (Autowert) der verlinkten Tabelle referenzieren.

Also mach ich nun erst ein SELECT auf die ID und gebe diese in der UPDATE WHERE Clausel mit:

Das Select Statement:
SQL:
SELECT [ID] FROM [ChangeCalendar: v_stefan] WHERE [Change ID] = ? AND Departement = ?

Die ID erhalte ich zurück und nun das Update Statement:
SQL:
UPDATE [ChangeCalendar: v_stefan]  SET [Change ID] = ?,[Departement] = ?,[Anfangszeit] = ?,[Endzeit] = ? WHERE [ID] = ?

Und tatsächlich tut sich was, das heisst zumindest ist die SQL Exception eine andere ;🙂
Java:
java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver] Operation must use an updateable query.
        at sun.jdbc.odbc.JdbcOdbc.createSQLException(Unknown Source)
        at sun.jdbc.odbc.JdbcOdbc.standardError(Unknown Source)
        at sun.jdbc.odbc.JdbcOdbc.SQLExecute(Unknown Source)
        at sun.jdbc.odbc.JdbcOdbcPreparedStatement.execute(Unknown Source)
        at synchronizer2.Sync.update(Sync.java:666)
        at synchronizer2.Sync.sync_change(Sync.java:209)
        at synchronizer2.Sync.<init>(Sync.java:130)
        at synchronizer2.MyTimer.work(MyTimer.java:114)
        at synchronizer2.MyTimer.access$000(MyTimer.java:24)
        at synchronizer2.MyTimer$1.run(MyTimer.java:65)
        at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
        at java.util.concurrent.FutureTask$Sync.innerRunAndReset(Unknown Source)
        at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

Hierzu gibt es nun reichlich Posts im Netz wobei die meisten auf ein Berechtigungsproblem zielen. Das wiederum kann ich nicht nachvollziehn, denn bevor ich update, lösche ich gewisse Datensätze und das geht tiptop. Allerdings benuze ich dafür kein PreparedStatement sondern:
SQL:
DELETE FROM [ChangeCalendar: v_stefan] WHERE (Anfangszeit < (now-30))

Könnte also sein, dass bronks doch recht hat und PreparedStatements mit Access nicht gehn. Warum das dann mit dem INSERT und PreparedStatement funktioniert hat.....:bahnhof:

Ich mach nun mal ein par Tests, mal schauen was dabei raus kommt.

Wenn noch jemand eine Rat weiss wäre ich sehr dankbar. Langsam weiss ich wirklich nicht mehr was ich noch probieren könnte.

Grüsse
nahum77
 
Du könntest noch eine Sache probieren: Laß testhalber die Anfangszeit und die Endzeit in Deinem Statement weg. Ich meine, daß es da zusätzlich ein Problem beim Parametrieren mit setDate() gibt, da es auf dem SQL Server auch schon mal Probleme damit gab.

Hier der Link:
Connection (Java 2 Platform SE 5.0)
Achso, ja! Ich dachte, daß Du ein Dokument zu Access gemeint hast.
 
Hallo zusammen

So ich denke ich habe das Rätsel gelöst!

Zuerst aber mal meine Erkenntnisse aus den Test:

1. PreparedStatement über JDBC:ODBC auf Ms Access funktionieren einwandfrei und ohne Einschränkung. Folgender Test schreib, liest, updatet, liest wieder und löscht schliesslich den Datensatzläuft und das ohne Probleme.

Java:
  private void test1() throws SQLException, InterruptedException {

    String changeID = "MyTest";
    String departement = "T";
    String anfangszeit = "2041-09-01 17:00:00";
    String endzeit = "2041-09-01 18:00:00";
    String freigabe = "Test";
    long id = -1L;

    System.out.println("Values:" + changeID + "; " + departement + "; " + anfangszeit + "; " + endzeit);

    String sql_insert = "INSERT INTO [" + mTablesAndColumns[1] + "] " + getInsert() + " VALUES " + getQM();
    System.out.println("SQL-Statement: " + sql_insert);
    mPSI = mTargetConn.prepareStatement(sql_insert);
    mPSI.setString(1, changeID);
    mPSI.setString(2, departement);
    mPSI.setString(3, anfangszeit);
    mPSI.setString(4, endzeit);
    mPSI.setString(5, freigabe);
    int rows = mPSI.executeUpdate();

    System.out.println("Anzahl INSERTS: " + rows);
 
    mPSI.close();

    String sql_getID = "SELECT [ID] FROM [" + mTablesAndColumns[1] + "] WHERE " + getWhere();
    System.out.println("SQL-Statement: " + sql_getID);
    mPSL = mTargetConn.prepareStatement(sql_getID);
    mPSL.setString(1, changeID);
    mPSL.setString(2, departement);
    ResultSet rs = mPSL.executeQuery();
    while (rs.next()) {
      id = rs.getLong("ID");
    }//end while
    System.out.println("ID = " + id);
   
    rs.close();
    mPSL.close();

    String sql_update = "UPDATE [" + mTablesAndColumns[1] + "] SET [Change ID] = ? WHERE [ID] = ?";
    System.out.println("SQL-Statement: " + sql_update);
    mPSU = mTargetConn.prepareStatement(sql_update);
    mPSU.setString(1, "Update:" + changeID);
    mPSU.setString(2, String.valueOf(id));
    rows = mPSU.executeUpdate();

    System.out.println("Anzahl UPDATE: " + rows);

    mPSU.close();

    String sql_changeID = "SELECT [Change ID] FROM [" + mTablesAndColumns[1] + "] WHERE [ID] = ?";
    System.out.println("SQL-Statement: " + sql_changeID);
    mPSL = mTargetConn.prepareStatement(sql_changeID);
    mPSL.setString(1, String.valueOf(id));
    ResultSet rsi = mPSL.executeQuery();
    while (rsi.next()) {
      changeID = rsi.getString("Change ID");
    }//end while
    System.out.println("ID = " + changeID);

    rsi.close();

    mPSL.close();

    String sql_del = "DELETE FROM [" + mTablesAndColumns[1] + "] WHERE " + getWhere();
    System.out.println("SQL-Statement: " + sql_del);
    mPSU = mTargetConn.prepareStatement(sql_del);
    mPSU.setString(1, changeID);
    mPSU.setString(2, departement);
    rows = mPSU.executeUpdate();

    System.out.println("Anzahl DELETE: " + rows);

    mPSU.close();

    System.out.println("Test1 done!\n\n");
  }

2. Der Verdacht, dass eine mit SharePoint verlinkte Tabelle nur über den Autowert updatet werden kann hat sich als falsch erwiesen. In der Where Clausel kann man nach beliebigen Spalten und Werten suchen.

3. Die Fehlermeldungen in den Exception sagen dir alles nur nicht wo das Problem liegt. Wie so oft war's ganz einfach. Ich habe die PreparedStatements nicht geschlossen und das führt wohl dazu, dass der Treiber oder die DB da was durcheinander bringt (Ev gibts dazu auch eine Restriktion die ich erst jetzt kennen gelernt habe...). Ich war mir bewusst, dass es nur ein ResultSet pro Statement geben kann, aber, dass es nur ein offenes PreparedStatement pro Connection geben darf habe ich verpasst 😳

Somit ist die Sache mit einem simplen
Java:
mPSI.close();
nach dem ausführen erledigt. 😱

Mein Konzept, die PreparedStatements als Members abzulegen und wieder zu verwenden, muss ich nun über den Haufen werfen. Naja halb so wild, erzeuge ich die PreparedStatements halt jedesmal neu.

Grüsse
Nahum77
 

Neue Themen


Zurück
Oben