2009-10-09 7 views
7

Ist es in SQL (SQL Server) möglich, die nächste ID (Ganzzahl) aus einer Identitätsspalte in einer Tabelle vor und ohne eine Zeile einzufügen? Dies ist nicht unbedingt die höchste ID plus 1, wenn die letzte Zeile gelöscht wurde.Abrufen der nächsten ID ohne Einfügen einer Zeile

Ich frage das, weil wir gelegentlich eine Live-DB mit neuen Zeilen aktualisieren müssen. Die ID der Zeile wird in unserem Code verwendet (zB Switch (ID) {Case ID:} und muss identisch sein. Wenn unsere Entwicklungs-DB und Live-DB nicht synchron sind, wäre es schön, vorher eine Zeilen-ID vorherzusagen vor der Bereitstellung.

I SET IDENTITY OFF natürlich konnte SET INSERT_IDENTITY ON oder eine Transaktion (tut dies Rolle der ID zurück?) usw., aber fragte sich, ob es eine Funktion, die die nächste ID zurückgegeben (ohne Inkrementieren es) laufen .

+0

Eine Transaktion wird den Identitätszähler nicht zurücksetzen, und es besteht immer das Risiko, dass ein anderer Thread die Nummer verwendet, von der Sie glauben, dass Sie sie später erhalten. – idstam

+0

Danke dafür @idstam Ich habe das vermutet. – iWeasel

Antwort

8

Edit:

Nach einer Anzahl von Stunden zu verbringen ganze Seite Dumps zu vergleichen, erkennen ich, es ein einfacher Weg ist, und ich soll auf dem DMVs bleibt von.

Der Wert überlebt eine Sicherung/Wiederherstellung, die ein klares Anzeichen dafür ist, dass es gespeichert wird - ich habe alle Seiten in der DB entleert und konnte die Position/Änderung für einen Datensatz wurde nicht gefunden. Vergleiche 200k Zeilen Dumps von Seiten macht keinen Spaß.

Ich hatte die dedizierte Admin-Konsole verwendet Ich nahm einen Dump von jeder einzelnen internen Tabelle ausgesetzt eine Zeile eingefügt und nahm dann einen weiteren Dump der Systemtabellen. Beide Dumps waren identisch, was darauf hindeutet, dass, während es überlebt hat und daher gespeichert werden muss, es selbst auf dieser Ebene nicht exponiert ist.

Also nachdem ich in einem Kreis herumgegangen bin, habe ich gemerkt, dass die DMV die Antwort hatte.

create table foo (MyID int identity not null, MyField char(10)) 
insert into foo values ('test') 
go 10 

-- Inserted 10 rows 
select Convert(varchar(8),increment_value) as IncrementValue, 
    Convert(varchar(8),last_value) as LastValue 
from sys.identity_columns where name ='myid' 


-- insert another row 
insert into foo values ('test') 

-- check the values again 
select Convert(varchar(8),increment_value) as IncrementValue, 
    Convert(varchar(8),last_value) as LastValue 
from sys.identity_columns where name ='myid' 

-- delete the rows 
delete from foo 


-- check the DMV again 
select Convert(varchar(8),increment_value) as IncrementValue, 
    Convert(varchar(8),last_value) as LastValue 
from sys.identity_columns where name ='myid' 

-- value is currently 11 and increment is 1, so the next insert gets 12 
insert into foo values ('test') 
select * from foo 

Result: 
MyID  MyField 
----------- ---------- 
12   test  

(1 row(s) affected) 

Nur weil die Zeilen entfernt wurden, wurde der letzte Wert nicht zurückgesetzt, daher sollte der letzte Wert + Inkrement die richtige Antwort sein.

Auch die Episode auf meinem Blog zu schreiben.

Oh, und die Abkürzung, um alles:

select ident_current('foo') + ident_incr('foo') 

Also eigentlich stellt sich heraus, einfach zu sein - aber das alles übernimmt niemand sonst Ihre ID verwendet hat, während Sie es zurückbekommen. Gut für die Untersuchung, aber ich würde es nicht im Code verwenden wollen.

+0

Huch! +1 für eine Antwort, die mich zum Lächeln brachte – iWeasel

+0

Ich habe die meiste Zeit der Nacht damit verbracht, sie zu recherchieren, dachte, sie würde für einen anständigen Blog-Artikel sorgen und es herausfinden. Bearbeiten meiner Antwort. – Andrew

+0

@Andrew. Der Gedanke, dass Sie zu viel Zeit in Ihren Händen haben, ist mir eingefallen. Auf der anderen Seite ein großes Dankeschön. Gute Antwort. – iWeasel

2

Anstatt eine Identity-Spalte, könnten Sie eine UNIQUE (GUID) Spalte als eindeutige Reihe identifer verwenden und bekannte Werte einfügen.

die andere Option S (die ich benutze) ist ET IDENTITY_INSERT ON, wobei die Zeilen-IDs in einem von der Quelle gesteuerten einzelnen "Dokument" verwaltet werden.

+1

Ausgezeichnete Punkt, aber Guids sind nicht wirklich praktisch auf diesem bestimmten Tisch und sind ein bisschen Platz hungrig. Ich verwende IDENTITY_INSERT im Moment. Es funktioniert, aber frage mich, ob es eine Alternative gibt. :) – iWeasel

+0

+1 für Guids. Guids haben im Vergleich zu einer Autoinkrement-Spalte eine Leistungseinbuße (obwohl der zusätzliche Platz, den sie hintereinander benötigen, trivial ist), aber sie machen es völlig überflüssig, durch solche Ringe zu springen. – MusiGenesis

+0

Die Strafe ist, wenn Sie die GUID als Clusterschlüssel verwenden, dann zahlen Sie einen hohen Preis in Bezug auf Leistung und Platz. – Andrew

2

Sie können ziemlich leicht feststellen, dass der letzte Wert verwendet wird:

SELECT 
    last_value 
FROM 
    sys.identity_columns 
WHERE 
    object_id = OBJECT_ID('yourtablename') 

Üblicherweise wird die nächste ID last_value sein + 1 - aber es gibt keine Garantie dafür.

Marc

+1

Genau; es gibt keine Garantie, weshalb ich mich gefragt habe, ob es eine Alternative gibt. :) – iWeasel

+0

Nein, es gibt keinen anderen Weg - SQL Server wird immer nur die ID wirklich ausgeben, wenn Sie tatsächlich das INSERT tun - keine Möglichkeit, das zu fälschen :-( –

2

Dies ist ein wenig seltsam, aber es funktioniert:

Wenn Sie den nächsten Wert wissen wollen, beginnen Sie den größten Wert immer plus eins:

SELECT max(id) FROM yourtable 

zu Damit dies funktioniert, müssen Sie die Identität beim Einlegen zurücksetzen:

Nicht Genau eine elegante Lösung, aber ich habe meinen Kaffee noch nicht getrunken ;-)

(Dies setzt voraus, dass der Prozess oder der Prozess zwischen dem ersten und zweiten Codeblock nichts an der Tabelle vorgenommen hat).

+0

Dies ist vielleicht nicht elegant, aber ich werde dies als die Antwort für Tabellen, wo Sie ziemlich sicher sein können, dass keine neue Zeile eingefügt wird, bevor Sie das ausführen. – iWeasel

+0

Entschuldigung Jeff, @Andrew verbrachte die ganze Nacht auf eine ausgezeichnete Bearbeitung. Funktioniert ein Leckerbissen. Haben Antwort neu zuordnen müssen. – iWeasel

7

versuchen IDENT_CURRENT:

Select IDENT_CURRENT('yourtablename') 

Dies funktioniert auch, wenn Sie alle Zeilen in der aktuellen Sitzung nicht eingeführt haben:

Gibt den letzten Identitätswert für eine angegebene Tabelle oder Sicht erzeugt . Der letzte erzeugte Identitätswert kann für jede Sitzung und jeden Bereich gelten.

+1

Nice.Dies ruft den zuletzt verwendeten Wert ab, und die MSDN-Seite warnt: "Seien Sie vorsichtig bei der Verwendung von IDENT_CURRENT, um den nächsten generierten Identitätswert vorherzusagen. Der tatsächlich generierte Wert kann sich von IDENT_CURRENT plus IDENTITY_SEED aufgrund von Einfügungen anderer Sitzungen unterscheiden." – PaulG

Verwandte Themen