![]() |
Datenbank: MSSQL • Version: 2005 • Zugriff über: ADO
Auto-Insertwert abfragen
Moin,
wie kann ich in diesem Konstrukt den Autoinc-Wert abfragen?
Delphi-Quellcode:
Die Table hat ein Feld mit dem Namen Aktenr, welches AUTOINC ist.
_stmp := 'select * from Akten';
_query := Tadoquery.Create(nil); with _query do begin connection := mus_Service.ADOConnMUS; try _query.sql.Text := _stmp; _query.open; insert; FieldValues['Datum_und_Zeit'] := Datum_und_Zeit; FieldValues['SenderIP'] := SenderIP; FieldValues['eMail'] := eMail; FieldValues['Telefon'] := Telefon; FieldValues['Mobile'] := Mobile; FieldValues['Art'] := Art; post; result := xxx; // Hier die Abfrage finally freeandnil(_query); result := 0; end; end; Gruss EL |
Re: Auto-Insertwert abfragen
Ich habe mal ein bisschen gegockelt und das Einzige, was ich finden konnte ist, sofort nach dem Insert die Identity abzufragen. Beispiel in PHP (von
![]()
Code:
$result = mssql_query("INSERT INTO STUFF(gaga,otherGaga) VALUES ('hello','apple'); SELECT @@IDENTITY as insertId;");
|
Re: Auto-Insertwert abfragen
Zitat:
Gruss EL |
Re: Auto-Insertwert abfragen
Nur ne idee, kenn mich mit MSSQL nicht aus, aber:
steht sowas nicht in ner System-tabelle? |
Re: Auto-Insertwert abfragen
Hallo,
mir ist da nur eine Möglichkeit bekannt, ein Select auf genau den Datensatz, den Du soeben eingefügt hast. Ins Unreine ungefähr so:
SQL-Code:
Sofern Du "alleine" auf der Datenbank unterwegs bist, also keiner parallel oder fast parallel Daten einfügen kann, dann könntest Du dank AutoInc auch mit
select AutoIncSpalte from Akten
where Datum_und_Zeit = :Datum_und_Zeit and SenderIP = :SenderIP and eMail = :eMail and Telefon = :Telefon and Mobile = :Mobile and Art = :Art
SQL-Code:
zum Ziel kommen. Fügen mehrere Personen, Programm... Daten ein, so scheitert das, da nicht sichergestellt ist, dass Dein Satz der Neueste ist und damit über diesen Wert verfügt.
select max(AutoInc_Spalte) from Akten
Stephan |
Re: Auto-Insertwert abfragen
Einfach nach dem Post den Wert in einer getrennten Abfrage auslesen.
SQL-Code:
(Scope_Identity() ist besser geeignet weil @@identity den wirklich letzten Auto Wert der aktuellen Session zurückgibt. Führt ein Insert in eine Tabelle einen InsertTrigger aus, der selbst wieder in eine andere Tabelle mit Autoinc Wert was einfügt, so gibt dir @@identity diesen letzten Wert zurück.
select Scope_Identity()
Angst um parallelen Zugriff muss man übrigens nicht haben, weil dieses Ganze Identity Auslesen Session bezogen ist, sich also auf eine Connection bezieht. Persönlich allerdings bevorzuge ich das Reservieren eines eindeutigen Werte bereits vor dem Insert (In anderen Datenbank als Sequenzen bekannt). Hier muss man allerdings darauch achten, dass die Ganze Spielerei transaktionssicher ist (sobald es mehr als eine SQL Anweisung ist kann es passieren, dass eine andere Session dazwischenfunkt). Hier z.B. mal der Code zum Nachahmen von Sequenzen unter MSSQL. Dazu noch eine geeignete Delphi Klasse zum Kapseln, und schon erhält man ganz easy bereits vorm Insert einen eindeutigen ID Wert auch ohne diese Identity Gedöhns (was einem z.B. bei .NET tierisch auf den Sack geht weil connectionslos gearbeitet wird).
SQL-Code:
Man beachte hier in der Stored Procedure das
CREATE TABLE [dbo].[Sequence] (
[SequenceName] [varchar] (255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL , [CurrentValue] [bigint] NOT NULL , [Increment] [int] NOT NULL , [CreationDate] [datetime] NOT NULL ) ON [PRIMARY] GO ALTER TABLE [dbo].[Sequence] WITH NOCHECK ADD CONSTRAINT [PK_Sequence] PRIMARY KEY CLUSTERED ( [SequenceName] ) ON [PRIMARY] GO ALTER TABLE [dbo].[Sequence] ADD CONSTRAINT [DF_Sequence_CurrentValue] DEFAULT (0) FOR [CurrentValue], CONSTRAINT [DF_Sequence_Increment] DEFAULT (1) FOR [Increment], CONSTRAINT [DF_Sequence_CreationDate] DEFAULT (getdate()) FOR [CreationDate], CONSTRAINT [CK_Sequence] CHECK ([Increment] <> 0) GO SET QUOTED_IDENTIFIER ON GO SET ANSI_NULLS ON GO CREATE PROCEDURE spNextSequence (@SequenceName varchar(255), @SequenceId bigint OUTPUT) AS DECLARE @Increment int SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION SP_GEN_ID SET @SequenceId = (Select CurrentValue from Sequence where SequenceName = @SequenceName) IF @SequenceId is null BEGIN insert into Sequence (SequenceName) values (@SequenceName) SET @SequenceId = (Select CurrentValue from Sequence where SequenceName = @SequenceName) END SET @Increment = (Select Increment from Sequence where SequenceName = @SequenceName) update Sequence set CurrentValue=CurrentValue+@Increment where SequenceName = @SequenceName SET @SequenceId = (Select CurrentValue from Sequence where SequenceName = @SequenceName) COMMIT TRANSACTION SP_GEN_ID GO SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GO
SQL-Code:
Damit wird sichergestellt, dass immer nur einer diese Prozedur gleichzeitig ausführen kann.
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
|
Re: Auto-Insertwert abfragen
Zitat:
Blöde Frage: Wie baue ich diesen: select Scope_Identity() in dieses Konstrukt ein?
Delphi-Quellcode:
with _query do begin
connection := mus_Service.ADOConnMUS; try sql.Text := _stmp; open; insert; FieldValues['Datum_und_Zeit'] := Datum_und_Zeit; FieldValues['SenderIP'] := SenderIP; FieldValues['eMail'] := eMail; FieldValues['Telefon'] := Telefon; FieldValues['Mobile'] := Mobile; FieldValues['Art'] := Art; post; result := ????? <======== HIER _query.Close; finally freeandnil(_query); result := 0; end; end; Gruss EL |
Re: Auto-Insertwert abfragen
Delphi-Quellcode:
with _query do begin
connection := mus_Service.ADOConnMUS; try sql.Text := _stmp; open; insert; FieldValues['Datum_und_Zeit'] := Datum_und_Zeit; FieldValues['SenderIP'] := SenderIP; FieldValues['eMail'] := eMail; FieldValues['Telefon'] := Telefon; FieldValues['Mobile'] := Mobile; FieldValues['Art'] := Art; post; result := LastIdentity; _query.Close; finally freeandnil(_query); //result := 0; --> Sonst wird dir nach aussen immer 0 ausgegeben end; end; function LastIdentity : integer; begin with _query do begin connection := mus_Service.ADOConnMUS; try sql.Text := 'Select Scope_Identity() as id'; open; if not(FielByName('id').IsNull) then result := FieldByName('id').asInteger; else result := 0; _query.Close; exit; finally freeandnil(_query); end; end; end ; |
Re: Auto-Insertwert abfragen
Zitat:
der liefert mir immer 0 als result :? Gruss EL |
Re: Auto-Insertwert abfragen
Und wenn Du in der Funktion eine eigene lokale Query erzeugst?
|
Re: Auto-Insertwert abfragen
Zitat:
Gruss EL |
Re: Auto-Insertwert abfragen
Delphi-Quellcode:
function LastIdentity : integer;
begin with TADOQuery.Create do begin //hier connection := mus_Service.ADOConnMUS; try sql.Text := 'Select Scope_Identity() as id'; open; if not(FielByName('id').IsNull) then result := FieldByName('id').asInteger; else result := 0; Close; finally Free; end; end; end ; |
Re: Auto-Insertwert abfragen
Zitat:
|
Re: Auto-Insertwert abfragen
Und mit @@IDENTITY statt Scope_Identity()? Aber ich möchte Jelly nicht in den Rücken fallen.
|
Re: Auto-Insertwert abfragen
Zitat:
Gruss EL |
Re: Auto-Insertwert abfragen
Hallo,
SQL-Code:
scheint erst dann einen Wert ungleich Null zu liefern, wenn mindestens ein Datensatz in der Tabelle ist. Liegt da eventuell das Problem?
Select Scope_Identity() as id
Stephan |
Re: Auto-Insertwert abfragen
Zitat:
nein - auch bei mehreren (im Moment 12 in der Testumgebung) Datensätzen immer 0 Gruss EL |
Re: Auto-Insertwert abfragen
Hallo,
Frage: Auch wenn Du die Abfrage im Management Studio machst? Wenn da ein anderes Ergebnis kommt, als im Programm, geht Dir "unterwegs" der Scope verloren, was ich nicht ausschließen möchte. Was liefert Dir denn
SQL-Code:
der holt wohl den höchsten vergebenen Wert zur ID-Spalte, der als Parameter übergebenen Tabelle.
select IDENT_CURRENT('Akten') as ID
Stephan |
Re: Auto-Insertwert abfragen
Zitat:
zunächst habe ich der Table ein Feld "neu" mit automatischen Inhalt 1 (nur 1, kein Increment) hinzugefügt. Obenauf einen Index drauf, damit die Suche ggfs. schneller geht. Somit hat immer genau der neue Datensatz neu=1. hier die Abfrage mit sofortiger Änderung neu=0;
Delphi-Quellcode:
Danke an alle, die geholfen haben :shock: - Mit diesem Workaround kann ich gut leben. Zumal dieses die einzige Stelle ist, an der der Datenbank neue Datensätze hinzugefügt werden.
function getaktennr : integer;
var _stmp : string; _query : Tadoquery; begin _stmp := 'select neu, Aktennr from Akten where neu=1'; _query := Tadoquery.Create(nil); with _query do begin connection := mus_Service.ADOConnMUS; _query.sql.Text := _stmp; _query.open; open; if (not eof) then begin result := FieldByName('Aktennr').asinteger; edit; FieldValues['neu'] := 0; post; end else result := 0; end; end; Gruss EL |
Re: Auto-Insertwert abfragen
Deine Lösung ist unschön wegen dem Extrafeld.
Lass doch mal in meinem Code dir Prüfung auf IsNull weg und versuche einfach den mit AsInteger zurückzugeben. Mit dem Scope_Identity() hatte ich noch nie Probleme, aber auch wohl deshalb vielleicht weil ich das so in der Form gar nicht mehr nutze. Ich plädiere definitiv zu der Lösung mit der Sequence Tabelle und der Stored Procedure aus ![]() |
Re: Auto-Insertwert abfragen
Habe jetzt nicht alles durchgelesen, aber in MSSQL 2005 gibt es auch etwas, ähnlich wie die returning clause aus Oracle oder Firebird.
Ich versuche normalerweise MSSQL nicht anzufassen, aber laut meinem SQL-Generator sollte das so aussehen:
SQL-Code:
Das ganze ist wie bei einem Returning aus Firebird eine Abfrage, die die Spalten in der Output clause als Ergebnismenge enthält.
INSERT INTO DeineTabelle(Feld1, Feld2)
OUTPUT inserted.ID VALUES(:Feld1, :Feld2) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz