wie erkennt man bei Verwendung von ADO am besten, ob ein
Datensatz wegen Primary Key-Verletzung / doppelter Schlüssel
nicht eingefügt werden konnte.
In ADO laufen ja leider sehr viele Fehler auf den Sammelfehler
&H80004005 - so auch hier, und dann kann man zusehen, woher
die Information für den konkreten Fehler kommt.
Außerdem: Die Methode zur Erkennung von "Doppelter Schlüssel"
sollte unabhängig vom eingesetzten Provider sein.
Dank an alle, die helfen wollen.
Gruß
Frank Lehmann
Hi Frank,
schau dir mal die eingebetteten Fehler an.
Ansonsten kann man mit einer Abfrage vorher (ggf. in einer Transaktion)
prüfen, was dann mit jedem Provider funktioniert.
--
Viele Grüße
Peter
db.Execute "if not exists (select * from test where id = " & id & ") " & _
"begin " & _
"print 'Eingefuegt';insert into test values(" & id &
",'" & Text & "')" & _
"end else print 'Existierte bereits'"
Ergebnis=db.Errors(0)
Ergebnis enthält dann "Eingefuegt" oder "Existierte bereits" in der Form
(z.B.) [Microsoft][SQL Native Client][SQL Server]Eingefuegt
[Microsoft][SQL Native Client][SQL Server]Existierte bereits
Wenn noch ein on error resume next vor dem Execute steht kommt hier auch die
Original-Fehlermeldung vom SQL Server an, also z.B.
[Microsoft][SQL Native Client][SQL Server]Der Name "Text1" ist in diesem
Kontext nicht zulässig. Gültige Ausdrücke sind Konstanten, konstante
Ausdrücke und (in bestimmten Kontexten) Variablen. Spaltennamen sind nicht
zulässig.
Ansonsten schließe ich mich meinem Vorredner an. Mit einer 2. Abfrage ist es
providerunabhängig.
Set rs = db.Execute("Select count(*) as existiert from test where id=" & id)
If rs("existiert") = 0 Then db.Execute "insert into test values(" & id &
",'" & Text & "')"
Gruß
Matthias
ich danke Euch für Eure Beiträge. Ist wahrscheinlich schwierig,
eine providerunabhängige Lösung zu finden.
Alle Lösungen, die den nativen Fehler über das ADO-Errorobjekt
aufklären, begeben sich in die Abhängigkeit eines bestimmten
Providers. Das ist so lange nicht nachteilig, wie man das Programm
ohnehin nur auf einen bestimmten DB-Typ loslässt.
Ätzend wird es allerdings, wenn das Programm z.B. mit Access
oder SQL-Server umschaltbar verwendet werden soll.
Dann macht das Aufklären des jeweiligen nativen Fehlers die
universelle Einsetzbarkeit von ADO mit beliebigen Providern
kaputt.
Providerunabhängig kommt man weiter, wenn man vor dem Einfügen
die Existenz des Datensatzes prüft. Das bedeutet aber einen Zugriff
auf die Datenbank mehr, als wenn man der DB-Zugriffssoftware
intern das Handling dieser Situation überlässt, die ja bei DAO eine
eigene Fehlernummer produziert, die nur für "Doppelter Schlüssel"
zuständig ist. "Einen Zugriff auf die Datenbank mehr" meine
ich deswegen, weil eventuell das "if not exists"-Konstrukt nicht jeder
DB-Typ verarbeitet, so dass man vorsichtshalber ein eigenes Select
verwendet, was nur die Existenz des Satzes prüft.
Damit hat man aber nur *einen* konkreten Fehler aus &H80004005
gefiltert. Es bleibt der Nachteil der gesamten ADO-Fehlerbehandlung,
eine Masse von spezifischen Fehlern auf einen Sammelfehler zu schieben
und es dem Anwender zu überlassen, irgendwie an die eigentliche
Ursache zu kommen.
Gruß
Frank Lehmann
> Providerunabhängig kommt man weiter, wenn man vor
> dem Einfügen die Existenz des Datensatzes prüft.
Dabei sollte man aber trotzdem - zumindest in
Mehrbenutzerumgebungen - beim Einfuegen eines
Datensatzes damit rechnen, dass ein anderer
Client gerade in diesem Moment einen Satz mit
derselben ID erstellt.
Da wuerde ich dann eher umgekehrt vorgehen ...
im Fehlerfall bei Einfuegen die Existenz des
Datensatzes pruefen. Haette auch den Vorteil,
dass es eben nicht permanent eine Zugriff mehr
gibt.
Aber so wirklich wuerde ich die Datenbank-
spezifischen in ein separates Modul packen (in
diesem Fall eine banale Konstante) oder - wenn
es ohne Programieraufwand sein soll - in einer
ini-Datei solche Definitionen auslagern.
Tschau
Ingo
on error resume next
db.Execute "Insert Into Test values(" & Text1.Text & ",'test')"
If db.Errors(0).SQLState =23000 then Msgbox "PK gibt es schon"
Das ist wesentlich sicherer als eine 2. Abfrage.
Gruß
Matthias
"Ingo Moch" <myjunkmail....@gmx.de> schrieb im Newsbeitrag
news:f0m5ke...@hamster.mochnet.de...
an den SQLState habe ich auch schon gedacht, aber ist der wirklich
providerunabhängig? In meinem Fall der erforderlichen Umschaltbarkeit
zwischen Access und SQL-Server verwendet Access z.B. als SQLState
für den doppelten Schlüssel 3022. Das entspricht exakt dem Fehlercode
aus DAO. Nur finde ich leider 3022 nicht unter den genormten SQLStates,
weder für doppelten Schlüssel noch irgend etwas anderes.
Wäre von Microsoft also schön gewesen, wenn sie beim Übergang auf
ADO nicht einfach ihre DAO-Codes in den SQLState geknallt hätten,
sondern sich überlegt hätten, ob man nicht einen Standard für SQLState
berücksichtigen müsste. Aber beim Erfüllen von Standards ist Microsoft
ja ohnehin Spitze.
Gruß
Frank Lehmann
"Matthias Vastring" <in...@vastring.de> schrieb im Newsbeitrag
news:D58E4C2F-80C3-461E...@microsoft.com...
> an den SQLState habe ich auch schon gedacht, aber ist der wirklich
> providerunabhängig? In meinem Fall der erforderlichen Umschaltbarkeit
> zwischen Access und SQL-Server verwendet Access z.B. als SQLState
> für den doppelten Schlüssel 3022. Das entspricht exakt dem Fehlercode
> aus DAO.
Hi Frank,
da in großem Umfang die gleichen Routinen bei ADO und DAO durch die JET
genutzt werden, ist das auch nachvollziehbar.
> Nur finde ich leider 3022 nicht unter den genormten
> SQLStates, weder für doppelten Schlüssel noch irgend etwas anderes.
In welcher Norm hast du denn geschaut? DIN????
> Wäre von Microsoft also schön gewesen, wenn sie beim Übergang auf
> ADO nicht einfach ihre DAO-Codes in den SQLState geknallt hätten,
> sondern sich überlegt hätten, ob man nicht einen Standard für SQLState
> berücksichtigen müsste. Aber beim Erfüllen von Standards ist Microsoft
> ja ohnehin Spitze.
Dass Microsoft beim Erfüllen von Standards Spitze sein soll, werden dir
bestimmt viele nicht glauben, vor allem, wenn der Standard erst nach dem
Erscheinen einer Software verabschiedet wurde.
Warum nutzt du nicht eine providerunabhängige Lösung ohne aufwendige Zeit
und Ressourcen kostende Fehlerunterbrechungen?
--
Viele Grüße
Peter
Einfügeoperation 1
db -> Insert Into Test values(777777,'test')
Resultat der Errors-Collection (db.Errors(0)) ---->
Fehler 3265 : Kein Objekt -> Alles OK
-----------------------------<
db2 -> Insert Into Test values(777777,'test')
Resultat der Errors-Collection (db2.Errors(0)) ---->
Fehler 3265 : Kein Objekt -> Alles OK
-----------------------------<
Einfügeoperation 2
db -> Insert Into Test values(777777,'test')
Resultat der Errors-Collection (db.Errors(0)) ---->
Description : [Microsoft][ODBC Microsoft Access Driver] Die von Ihnen
vorgenommenen Änderungen an der Tabelle konnten nicht vorgenommen werden, da
der Index, Primärschlüssel oder die Beziehung mehrfach vorkommende Werte
enthalten würde. Ändern Sie die Daten in den Feldern, die gleiche Daten
enthalten, entfernen Sie den Index, oder definieren Sie den Index neu, damit
doppelte Einträge möglich sind, und versuchen Sie es erneut.
NativerError : -1605
Number : -2147217900
Source : Microsoft OLE DB Provider for ODBC Drivers
SQLState : 23000
-----------------------------<
db2 -> Insert Into Test values(777777,'test')
Resultat der Errors-Collection (db2.Errors(0)) ---->
Description : [Microsoft][ODBC SQL Server Driver][SQL Server]Verletzung
der PRIMARY KEY-Einschränkung 'PK_test'. Ein doppelter Schlüssel kann in das
'dbo.Test'-Objekt nicht eingefügt werden.
NativerError : 2627
Number : -2147217900
Source : Microsoft OLE DB Provider for ODBC Drivers
SQLState : 23000
-----------------------------<
Also, bei mir kommt 23000 als SQLState. Gleiches Ergebnis bekomme ich auch
mit dem "Microsoft OLE DB Provider for SQL Server"
Habe die MS KB mal befragt, da steht:
SQLSTATE
SQLSTATE ist ein aus fünf Zeichen bestehender Fehlercode, der ursprünglich
in der ODBC-Spezifikation definiert wurde. SQLSTATE-Fehlercodes sind in
allen ODBC-Treibern vorhanden und stellen eine Möglichkeit zur Codierung der
grundlegenden Fehlerbehandlung von Anwendungen dar, ohne dass Tests für die
verschiedenen Fehlercodes durchgeführt werden müssen, die von den
verschiedenen Datenbanken zurückgegeben werden. Der ODBC SQLSTATE-Fehlercode
von ODBC hängt in keiner Weise mit dem Statusattribut von Database Engine
(Datenbankmodul)-Fehlermeldungen zusammen.
ODBC 2.x gibt einen einzelnen Satz von SQLSTATE-Codes zurück, während ODBC
3.x einen Satz von SQLSTATE-Codes zurückgibt, die auf den Standard X/Open
Data Management,Structured Query Language (SQL), Version 2, abgestimmt sind.
Da alle ODBC-Treiber die gleichen Sätze von SQLSTATE-Codes zurückgeben,
können Anwendungen, deren Fehlerbehandlung auf SQLSTATE-Codes aufbaut,
leichter portiert werden.
Poste doch mal ein deinen Provider, ich probiere das denn mal aus.
Gruß
Matthias
"Frank Lehmann" <f.le...@chat4world.com> schrieb im Newsbeitrag
news:O$n9McxhH...@TK2MSFTNGP06.phx.gbl...
dass es für die SQLState-Codes einen Standard geben könnte, entnehme
ich z.B.
http://msdn2.microsoft.com/en-us/library/ms681570.aspx
Durch Googelei findet man auch noch andere Quellen, die der Meinung
sind, ihr SQLState erfüllt einen ANSI SQL Standard.
http://cenmvst.gov.ab.ca/bookmgr-cgi/bookmgr.exe/BOOKS/BOOKREAD.MVSBASE.DSNMC0A1.BOOK/2.1.4?SHELF=BO
OKREAD.TEST.BKSHELF
Gruß
Frank Lehmann
"Peter Fleischer" <peter.fleis...@gmx.de> schrieb im Newsbeitrag
news:uZokLhxh...@TK2MSFTNGP02.phx.gbl...
dass das bei Dir auch mit Access funktioniert, liegt daran, dass
Du den Zugriff über ODBC realisierst. Hier spielt sich die einheitliche
ODBC-Schnittstelle in den Vordergrund.
Ich hingegen verwende für Access mit ADO den Microsoft OLE DB
Provider for Jet 4.0.
Auf Access mit ADO und darin noch mal mit ODBC zuzugreifen, ist
nach meiner Kenntnis ein Zugriffscontainer zuviel und mit Access-ODBC
auch nicht mehr up-to-date.
So wie ODBC in der Lage ist, den Zugriff auf verschiedene DB-Typen
beim Auftreten des Fehlers "Doppelter Schlüssel" auf einen einheitlichen
SQLState zu kanalisieren, hätte ich mir das bei OLE DB als Nachfolger
von ODBC auch gewünscht, nämlich dass immer dieselbe spezifische
Fehlernummer für den Fehler "Doppelter Schlüssel" geliefert wird,
egal mit welchem DB-Typ man verbunden ist.
Gruß
Frank Lehmann
> dass es für die SQLState-Codes einen Standard geben könnte, entnehme
> ich z.B.
> http://msdn2.microsoft.com/en-us/library/ms681570.aspx
Hi Frank,
da steht aber nichts von IEEE, DIN, Gost oder sonstwas, was auf einen
verabschiedeten Standard hinweist.
> Durch Googelei findet man auch noch andere Quellen, die der Meinung
> sind, ihr SQLState erfüllt einen ANSI SQL Standard.
>
> http://cenmvst.gov.ab.ca/bookmgr-cgi/bookmgr.exe/BOOKS/BOOKREAD.MVSBASE.DSNMC0A1.BOOK/2.1.4?SHELF=BO
> OKREAD.TEST.BKSHELF
Da steht:
SQLSTATE provides application programs with common codes for common error
conditions (the values of SQLSTATE are product-specific only if the error or
warning is product-specific).
Ein Hinweis zu einem IEEE-Standard zum ANSI SQL, wo die Grenze zwischen
produktspezisch und allgemeingültig ist, fehlt auch dort.
--
Viele Grüße
Peter
Erfolgreich getestet habe ich jetzt mit
Driver={Microsoft Access Driver (*.mdb)
Driver={SQL Server}
Driver={SQL Native Client}
Provider=sqloledb;
Provider=SQLNCLI;
Einzig die Abfrage auf Access über JET
Provider=Microsoft.Jet.OLEDB.4.0;
geht nicht, was ja aber klar ist.
Ich bleibe bei ODBC, da klappt alles :-). Aber ging es nicht eigentlich um
eine möglichst unabhängige Lösung. Da ist ODBC die bessere Wahl (auch wenn
ich gleich geprügelt werde :-))
Gruß
Matthias
"Frank Lehmann" <f.le...@chat4world.com> schrieb im Newsbeitrag
news:uRoHfByh...@TK2MSFTNGP02.phx.gbl...
bei
http://msdn2.microsoft.com/en-us/library/ms681570.aspx
steht
"Returns a five-character String value that follows the ANSI SQL standard and indicates the error
code."
Bei
http://cenmvst.gov.ab.ca/bookmgr-cgi/bookmgr.exe/BOOKS/BOOKREAD.MVSBASE.DSNMC0A1.BOOK/2.1.4?SHELF=BO
OKREAD.TEST.BKSHELF
steht
"The coding scheme is the same for all database managers and is
consistent with the proposed ISO/ANSI SQL2 standard."
Wäre nun zu prüfen, ob proposed irgendwann mal approved geworden ist.
Gruß
Frank Lehmann
"Peter Fleischer" <peter.fleis...@gmx.de> schrieb im Newsbeitrag
news:#WQqdQyh...@TK2MSFTNGP03.phx.gbl...
ja, es liegt an JET. Aber der Microsoft OLE DB Provider for Jet ist
nicht DAO, sondern eine Neuentwicklung, und dabei hätte ich mir
wie gesagt gewünscht, dass MS Standards für die Fehlercodes
von SQLState implementiert hätte.
Gruß
Frank Lehmann
"Matthias Vastring" <in...@vastring.de> schrieb im Newsbeitrag
news:A466B702-513B-4C2F...@microsoft.com...
Hi Frank,
mich interessiert brennend, auf welchen verabschiedeten Standard sich diese
unverbindliche Aussage beziehen soll.
--
Viele Grüße
Peter
Du kannst natürlich eine Abfrage "zwischenschalten".
Wenn die Source=Microsoft JET Database Engine -> Ehem. DAO-Code
In allen anderen Fällen X/Open Data Management-Code
Damit ist es dann "semi-universell".
Gruß
Matthias
"Frank Lehmann" <f.le...@chat4world.com> schrieb im Newsbeitrag
news:OioFpdyh...@TK2MSFTNGP05.phx.gbl...
"Matthias Vastring" schrieb:
> Richtig, JET ist aber der "Nachfolger",
> weil es DAO in net nicht mehr gibt.
Nein. DAO hat direkt auf die Jet-Engine
zugegriffen, waehrend ADO ueber den
OLEDB-Treiber auf Jet zugreift.
Die Aufgabe von eine Treiber ist es nun
mal zwischen propitaerer Technik und
standardisierter Zugriffs-Engine zu
vermitteln. Von daher waere es auch die
Aufgabe des OLEDB-Treibers die
Meldungscodes fuer SQLState zu mappen.
Mircosoft hat hier selbst einen Quasi-
Standard geschaffen, den sie bei der
Jet-Engine missachten.
[Mehfach-TOFU entfernt]
http://einklich.net/usenet/zitier.htm
Tschau
Ingo
Habs doch extra in Anführungszeichen gesetzt. DAO/JET gibt es in .net nicht
mehr (soweit mir bekannt - wehe wenn doch!), und der "OLE DB Provider for
Jet", also ADO/JET, gibt die Fehlermeldungen kompatibel zum alten DAO/JET.
Hab gerade noch mal bei MS geschaut und folgenden Text gefunden (bezüglich
des SQLState)
' SQLState is actually a SQL92 error reporting construct that
' isn't used by the Jet database engine. The DAO values are
' provided for backward compatibility with existing and
' migrating applications. In general, clients will want to
' use internal errors instead of IDA/DAO errors.
Genau genommen hätte ich also schreiben sollen "ADO/JET ist der Nachfolger
von DAO/JET", ok?
Gruß
Matthias