verwendetes Datenbanksystem: <Microsoft SQL Server 2005>
Hallo nochmal:
Ich habe folgende Frage, wenn ich datensätze anlege möchte ich selbst die Id für den Datensatz setzen.
Also, wenn ein Datensatz eingefügt wird habe ich immer eine Liste genommen, alle Datensätze reingeladen und dann die höchste Id + 1 genommen, also hatte ich eine neue Id.
Was mich ärgert ist, wenn ich die ersten 5 Datensätze(Id 1-5) lösche, sind diese Ids wieder verfügbar und mit einer Liste will man auch nicht immer zu tun haben. Stellt euch mal vor es sind 1 Millionen Datensätze....jetzt bin ich da etwas ratlos!!
Kann mir jemand helfen? Ich muss die Logik selber programmieren. Kann da jemand helfen?
Beste Grüße und danke im Voraus
Kevin Winter
Frage: warum willst du die id selber festlegen wenn du eh die nächst höhere suchst, dafür gibt es doch primary keys und autoincrement.
"Programming is similar to sex. If you make a mistake, you have to support it for the rest of your life."
Das darf ich nicht verwenden, ich muss die Logik aus dem Programm steuern 🙂
Ist etwas doof. Würde mich übere eine Funktion oder einer Klasse freuen die sowas in der Richtung anstellt.
Hoffe da kann mir einer weiterhelfen 😉
Gruß Kevin
dann mach doch einfach select max(id) from .....
result + 1
"Programming is similar to sex. If you make a mistake, you have to support it for the rest of your life."
Denk nur daran, dass nichts schiefgeht wenn zwei zur gleichen Zeit das vorhaben.
huhu,
Warum "darfst" Du das nicht? Wenn es ein Programmierbeispiel für die Schule ist, dann "max(ID) + 1" + Transaktion (für die Schule ...) - aber es ist in meinen Augen sinnlos wenn die DB einen autoincrement anbietet. Diesen kann man auch bei einem Insert zurückbekommen. Zur Not noch eine GUID mit einfügen und nochmal selektieren.
Schau Dir noch Datasets, ORMapper usw. an, die machen das intern, ohne dass Du als Programmierer etwas tust - in deinem Fall also auch "durch programmieren" gelöst. Und: SQL ist auch eine Programmiersprache, ergo auch die Tabellen mit Autoincrtement.
🙂
Xynratron
Edit: Präzisiert
Herr, schmeiss Hirn vom Himmel - Autsch!
Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.
Denk nur daran, dass nichts schiefgeht wenn zwei zur gleichen Zeit das vorhaben.
Das geht auch schief, sobald du mehr als eine gleichzeitige Transaktion verwendest. Bitte verwende Auto_Increment dafür.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
Was ist mit "Select @@Identity"? Da bekommt man doch die letzte insert ID.
Ich kenne allerdings den MSSQL gar nicht und zum Glück hat Oracle Sequences.
Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!
YARRRRRR!
Denk nur daran, dass nichts schiefgeht wenn zwei zur gleichen Zeit das vorhaben
Das macht man so (einfache Art und Weise) :
Höchste ID holen (select max), um eins erhöhen, Datensatz einfügen. Wenns nicht klappt dann ID um eins erhöhen und nochmal einfügen. Solange bis es klappt.
Autoincrement ist natürklich besser.
Bei Oracle muss man dafür am meisten programmieren 😉
Grüße Bernd
Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3
Was ist mit "Select @@Identity"?
SELECT @@Identity liefert ja nur die ID des zuletzt eingefügten Datensatzes zurück. Und es wäre unter MSSQL fatal damit die nächste ID zu ermitteln (z.B. SELECT @@Identity + 1).
Ich kenne mich mit Oracle nicht wirklich gut aus, was meinst du mit Sequences? Auto-Increment?
"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)
Select @@Identity + 1 funktioniert nicht als neue ID, da @@Identity nur die zuletzt eingefügt Auto-ID der aktuellen Transaktion zurückgibt und nicht wie gewünscht den Max(ID)-Wert.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
Was ist mit "Select @@Identity"?
SELECT @@Identity liefert ja nur die ID des zuletzt eingefügten Datensatzes zurück. Und es wäre unter MSSQL fatal damit die nächste ID zu ermitteln (z.B. SELECT @@Identity + 1).Ich kenne mich mit Oracle nicht wirklich gut aus, was meinst du mit Sequences? Auto-Increment?
Oracle kennt kein Auto-Increment. In Oracle hast du Sequences bei denen du den Step, den Start und die Max Value angeben kannst. Dann musst du mit einem Trigger immer aSequence.NextVal in die entsprechende ID column schreiben.
Das ist schon ein wenig aufwendiger als mit Auto-Increment columns, aber auch flexibler und schlussendlich kann man Sequences dann auch für ganz andere Zwecke einsetzen (z.B. in dem man cycle setzt).
Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!
YARRRRRR!
Was ist mit "Select @@Identity"? Da bekommt man doch die letzte insert ID.
@@Identity liefert die letzte ID in der Session (kann also auch z.B. die ID aus einer anderen Tabelle sein, nur weil ein Trigger etwas eingefügt hat).
Select SCOPE_IDENTITY() liefert die letzte eingefügte ID bezogen auf Session und Scope. (Also nicht das Triggerverhalten von @@Identity):
IDENT_CURRENT(’tablename’) liefert die letzte eingefügte ID zu einer gegebennen Tabelle - unabhängig von Session und Scope.
Zusammenfassend kann man sagen: nutzt immer Scope_Identity() um nach dem einfügen eure ID zu bekommen.
🙂
Xynratron
Herr, schmeiss Hirn vom Himmel - Autsch!
Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.
Ich persönlich verabscheue diese AutoIncrement Geschichte. Ich möchte schon oft vor dem Speichern in der DB wissen, welche ID der Datensatz erhält, weil ich bevorzugt die Leute im RAM arbeiten lasse, und beim Speichern werden dann alle Änderungen gleichzeitig in einer Transaktion zurückgeschrieben. Ginge sicherlich auch mit Identity, aber ich hab mir, bedingt durch fehlende Sequence Funktionalität im SQL Server, ein eigene Tabelle und eine SP erstellt, die mir die nächste ID liefert. Das ganze ist transactionssicher. Wens interessiert, hier die Codeschnipsel (mit zugehöriger .NET Wrapperklasse)
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 OFF
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
public class Sequence
{
/// <summary>
/// Retrieves a next Id for the provided sequence name
/// </summary>
/// <param name="conn">An open SqlConnection</param>
/// <param name="seqName">The sequencename, that needs to be identical to the related tablename</param>
/// <returns>The new sequence value. If an error occured, -1 is returned</returns>
public static Int64 Next(SqlConnection conn, String seqName)
{
try
{
SqlCommand cmd = new SqlCommand("spNextSequence", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@SequenceName", seqName);
SqlParameter sequenceId = new SqlParameter();
sequenceId.ParameterName = "@SequenceId";
sequenceId.SqlDbType = SqlDbType.BigInt;
sequenceId.Direction = ParameterDirection.Output;
cmd.Parameters.Add(sequenceId);
cmd.ExecuteNonQuery();
return Convert.ToInt64(cmd.Parameters["@SequenceId"].Value);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
return -1;
}
}
}
@Jelly: Auf ähnliche Weise mach ich das auch.
Ich habe eine unabhängige Tabelle, die mir die höchsten vergebenen IDs anderer Tabellen speichert. Das wird beim Speichern des Datasets für jeden Wert angepasst und an die jeweilige Tabelle weitergereicht. Das gibt auch bei Mehrbenutzerbetrieb keine Probleme.
gegrüßt!
Wer beim Gewächshaus sitze, werfe nie den ersten Elefanten.