Hallo, in mnachen SQL-Tabellen sind ja Spalten enthalten, die automatisch eine laufende ID erzeugen, wenn ein neuer Eintrag vorgenommen wird. Gibt es eine Möglichkeit, diese automatisch erzeugte ID direkt nach dem Insert-Befehl ohne eine spezielle zusätzliche Abfrage zu bekommen ? (manchmal sind die neu eingetragenen Daten ja nicht eindeutig abfragbar, sondern die beste Referenz ist tatsächlich die automatisch angelegte ID) Danke, Interrupt
interrupt schrieb: > Gibt es eine Möglichkeit, diese automatisch erzeugte ID direkt nach dem > Insert-Befehl ohne eine spezielle zusätzliche Abfrage zu bekommen ? > (manchmal sind die neu eingetragenen Daten ja nicht eindeutig abfragbar, > sondern die beste Referenz ist tatsächlich die automatisch angelegte ID) ganz ohne Abfrage geht es nicht. Beim SQL-Server musst du die Variabel @@IDENTITY abfragen. insert into test .... select @@IDENTITY es gibt nur ein paar Fallstricke, wenn noch Trigger mit beteiligt sind.
For example, after inserting a row that generates an AUTO_INCREMENT value, you can get the value like this: mysql> SELECT LAST_INSERT_ID(); -> 195
Zumindest in Perl gibt es die Möglichkeit, da kommt dann als Teil der API die ID zurück. Der Haken ist, dass das nicht mit jeder Datenbank und jedem Treiber funktioniert. Daher vermute ich mal, dass das kein allgemeines SQL ist, sondern eine Eigenschaft der verwendeten Datenbank.
Um welches SQL und welchen Treiber geht es? http://nl1.php.net/manual/en/mysqli-stmt.insert-id.php http://nl1.php.net/manual/en/pdo.lastinsertid.php https://mariadb.com/kb/en/mariadb/mysql_stmt_insert_id/ Nur die ersten Beispiele, die mir so in den Sinn kommen, auf den unterschiedlichsten Abstraktionsebenen.
Das ganze soll mit einem Programm, das in C++ geschrieben wurde und mit einer Microsoft SQL -Datenbank laufen, Trigger sind in dem Zusammenahng nicht vorgesehen.
interrupt schrieb: > Das ganze soll mit einem Programm, das in C++ geschrieben wurde und mit > einer Microsoft SQL -Datenbank laufen, Trigger sind in dem Zusammenahng > nicht vorgesehen. dann verwende das "select @@IDENTITY" nach dem Insert.
Du kannst auch mit OUTPUT die betroffenen Datensätze eines Insert/Update abfragen (https://msdn.microsoft.com/en-us/library/ms177564.aspx) Das hat den vorteil, dass du wirklich alle betroffenen Zeilen bekommts. Mit dem select @@IDENTITY bekommst du nur den letzten Eintrag (im Folgenden Beispiel den Eintrag mit dem Text 'Bar')
1 | /* |
2 | CREATE TABLE [dbo].[Test]( |
3 | [ID] [int] IDENTITY(1,1) NOT NULL, |
4 | [Text] [nvarchar](50) NOT NULL, |
5 | CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED |
6 | ( |
7 | [ID] ASC |
8 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] |
9 | ) ON [PRIMARY] |
10 | */ |
11 | |
12 | DECLARE @tmp TABLE(ID INT, Text NVARCHAR(50)) |
13 | |
14 | INSERT INTO Test (Text) |
15 | OUTPUT Inserted.ID, Inserted.Text INTO @tmp |
16 | VALUES |
17 | ('Foo'), |
18 | ('Bar') |
19 | |
20 | SELECT * FROM @tmp |
Danke soweit, werde ich testen. Noch eine Anschlussfrage : Bisher (bis incl. Win7) erfolgt der Zugriff auf die MSSQL-Datenbank über eine ODBC-Schnittstelle. Funktioniert das auch mit Win10 und / oder gibt es da eine bessere Lösung für Programme, die mit C++ (GNU C-Compiler mit Eclipse) geschrieben sind ?
interrupt schrieb: > Bisher (bis incl. Win7) erfolgt der Zugriff auf die MSSQL-Datenbank über > eine ODBC-Schnittstelle. > Funktioniert das auch mit Win10 und / oder gibt es da eine bessere > Lösung für Programme, die mit C++ (GNU C-Compiler mit Eclipse) > geschrieben sind ? Für C++ ist ODBC das richtige. Wenn auch manchmal etwas umständlich. Es gibt zwar noch den NativeClient, aber das würde ich nicht empfehlen.
LASTINSERTID ist etwas, wenn du nur einen client oder nur wenige gleichzeitige Zugriffe hast. Andernfalls solltestdudas anders machen denn, oft sieht man so einen Unsinn auch in DB-Anwendungen, wo jemand auf die Idee kam, dann nachträglich das ganze multiuserfähig zu machen. Beispiel: dein c++Programm als DB-client wird auf zwei PCs ausgeführt, beide User arbeiten völlig parallel und unabhängig voneinander. Zeitstempel PC SQL 09:05:23.00001 PC1 "INSERT INTO ..." 09:05:23.00004 PC2 "INSERT INTO...." nun kommt die Rückfrage wie oben angegeben 09:05:23.00005 PC1 "LASTINSERTID...." und bekommt die ID vom Insert des PC2. Es wird zwar behauptet, daß lastInsertId connectionabhängig sein soll, aber das habe ich bislang nicht feststellen können. Achja: ich habe hier auch schon "kommerzielle Software" erwischt, bei denen zwischen den SQL-befehlen INSERT und lastInsertID ca 0,8sek vergingen... Sicherer ist: SELECT id FROM table WHERE <viele Daten des insert> ORDER BY id DESC LIMIT 1; Funktioniert natürlich nur, wenn die Summe der daten in INSERT unique genug sind. Solltest du aber immer wieder diesselben Daten per INSERT eintragen wollen, wäre wohl eine DB eh kaum der richtige Speicherort.
Andy schrieb: > Sicherer ist: > SELECT id FROM table WHERE <viele Daten des insert> ORDER BY id DESC > LIMIT 1; nur ist das das langsamste. Da es hier um MS-SQL geht ist @@IDENTITY das richtige das ist 100% Session abhängig und macht keine Probleme. In mysql ist es LAST_INSERT_ID(). deine Lösung ist sehr schlecht. Sie ist langsam und braucht zu viele Resourcen. Könnte man verschmerzen wenn sie wenigsten Plattformunabhängig währe das ist sie aber auch nicht. Bringt also nur Nachteile gegenüber LAST_INSERT_ID():
Andy schrieb: > multiuserfähig ... ist MS SQL (wie auch praktisch jede andere Datenbank), wenn man Transaktionen korrekt benutzt.
Clemens L. schrieb: > Andy schrieb: >> multiuserfähig > > ... ist MS SQL (wie auch praktisch jede andere Datenbank), wenn man > Transaktionen korrekt benutzt. richtig, aber für arbeiten mit ident spalten braucht man keine Transaktionen.
ein Select auf ein PrimKey, mit einer Datenmenge von max 1 Datensatz, der eben erst eingesetzt wurde. Wenn ein Db-Server das nicht aus seinen Cache bedienen kann, dann ist der ... suboptimal konfiguriert. Wenn man das richtig macht, sollte das kaum langsamer als last_insertID sein. Und wie gesagt: es ist defninitv sicherer nach meinr Erfahrung. YMMW.
Andy schrieb: > ein Select auf ein PrimKey, mit einer Datenmenge von max 1 Datensatz, > der eben erst eingesetzt wurde. Wenn ein Db-Server das nicht aus seinen > Cache bedienen kann, dann ist der ... suboptimal konfiguriert. schon das parsen vom SQL braucht resourcen. Dann müssen die Daten noch sortiert werden. Dann brauchst du noch zwingend ein Index auf der ID spalte. > Wenn man das richtig macht, sollte das kaum langsamer als last_insertID > sein. Und wie gesagt: es ist defninitv sicherer nach meinr Erfahrung. > YMMW. man liest einfach die Doku, darin steht wie man so etwas zu verwenden hat. Bei Mysql steht eindeutig drin: [...] The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own. This behavior ensures that each client can retrieve its own ID without concern for the activity of other clients, and without the need for locks or transactions. [...] Vermutlich war das Problem bei dir an einer anderen stelle.
Ich verwende bei MSSQL meist scope_identity(): http://stackoverflow.com/a/1920640 Die "Lösung" von Andy kann man höchstens noch als Hack durchgehen lassen.
Jan H. schrieb: > Ich verwende bei MSSQL meist scope_identity(): > http://stackoverflow.com/a/1920640 Danke, selbst nach 10 Jahren aktiven SQL lernt man nicht aus. Aber wie sind eh weg von Identity (hat bei uns Nachteile) und damals gab es nur @@IDENTITY (SQL Server < 2008)
Peter II schrieb: > Vermutlich war das Problem bei dir an einer anderen stelle. Schön wärs, denn das, was da im Manual drinsteht, kenn ich auch so. Ich trau dem ganzen nicht mehr 100%tig (ich habe halt in der freien Wildbahn auch gegenteiliges gesehen) Am häufigsten habe ich Auswirkungen von falschen Rückgaben durch LastInsertID bei einer WaWi gesehen (per Mitschnitt der SQL-Verbindung), allerdings war das eine ins win7-Zeitalter gehobene Delphi-Anwendung mit ODBC-treiber älter Art. Hier habe ich für die Zeitspanne von INSERT zu Last_insert_ID schonmal 0,6sek beobachten können. Vermutlich wegen der langsamen programminternen Ausführungszeit (nein, selbst Zugriffe durch PHP-Scripte auf die DB laufen getesteterweise um Größenordnungen schneller!) und damit der langen Zeitabstände fiel das hier besonders häufig auf. Ein anderer (test-) MSSQL mit quasi fast leeren Tabellen half nicht und brachte gleiche Ergebnisse. Wenn ihr das so einsetzen wollt, bitteschön. Wenn ihr dann Probleme bekommt, denkt ggf an meine Erfahrungen und zieht auch dies als mögliche Fehlerquelle in Erwägung. An sowas denkt doch keiner, der das "SQL-Handbuch" kennt. Schaden kanns nicht.
Andy schrieb: > Wenn ihr das so einsetzen wollt, bitteschön. Wenn ihr dann Probleme > bekommt, denkt ggf an meine Erfahrungen und zieht auch dies als mögliche > Fehlerquelle in Erwägung. An sowas denkt doch keiner, der das > "SQL-Handbuch" kennt. Schaden kanns nicht. deine Lösung bringt doch viel mehr Probleme. Der Datensatz kann schon lange vom nächsten gelöscht wurden sein. Also muss man mit Transaktionen arbeiten - was sinnlos lang die Tabelle blockiert. von deiner Lösung kann man nur abraten.
Peter II schrieb: >... Der Datensatz kann schon > lange vom nächsten gelöscht wurden sein. Dann findet das SELECT den Datensatz auch nicht. Wenn der Datensatz berechtigerweise gelöscht oder geändert wurde, dann ist das halt ein normaler Betriebsstatus, mit dem das Programm klarzukommen hat. (im einfachsten Fall üblicherweise eine Fehlerbehandlung) Das kann dir auch bei deiner Lösung passieren: Wer garantiert, daß nach Übergabe des PrimKeys aus @@Identity nicht schon das DELETE in der Queue steht (oder gar durch eine andere Session abgearbeitet wird)? Noch bevor ich sinnvoll (außer vllt als debug-ausgabe) mit dem primkey arbeiten kann, hab ich einen PrimKey zur Weiterverarbeitung, der in der tabelle nicht mehr existiert. Wiederum die frage, ob das eingeplant ist. So oder so ist das Beispiel unglücklich gewählt. Ich verstehe, worauf du hinauswillst und ich sage: verlaß dich nicht zu 100% drauf.
Ich würde das ganze evtl. von der anderen Seite mal betrachten. Du willst in ne DB einen Eintrag hinzufügen, der dann später nicht mehr eindeutig referenzierbar ist? (Über seine Daten, ohne die ID). Für was solltest du dann die ID benötigen? Für mich bedeutet das nur, dass du u.U. 2 gleiche Datensätze in der DB hast, die sich nur anhand der ID unterscheiden. Dann gibt es 2 Ansätze: - Dein DB-Schema ist scheisse und du solltest dir Gedanken darüber machen ob du in der falschen Normalform bist. - Es kann einfach auf Grund deiner Daten passieren, dass du 2 oder mehr gleiche Datensätze hast. Wofür musst du die Daten unmittelbar nach dem Einfügen mit der ID referenzieren? Bzw. wofür brauchst du diese ID? Was willst du weiterhin mit der ID machen?
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.