Ich will in einer großen Tabelle (mehrere 10.000 Datensätze) mittels einer Stored Procedure Datensätze in die Datenbank übertragen. Während der Übertragung soll die Stored Procedure gleich direkt abprüfen, ob der Satz bereits enthalten ist, und nur wenn er nicht enthalten ist soll der INSERT erfolgen.
Der Index der Datensätze erstreckt sich in diesem Fall über mehrere Felder (Datum, Personalnummer, Buchungstyp).
Mittels einer Stored Procedure kann man das so lösen:
CREATE PROCEDURE dbo.sp_test @col1 NVARCHAR(50), @col2 NVARCHAR(50), @col3 NVARCHAR(50), @col4 NVARCHAR(50) AS BEGIN SET NOCOUNT ON
IF EXISTS (SELECT 1 FROM bulkinsert WHERE (col1 = @col1) and (col3 = @col3) and (col4 = @col4) ) RAISERROR('This value already exists.', 11, 1) ELSE INSERT bulkinsert(col1,col2,col3,col4) VALUES(@col1,@col2,@col3,@col4) END GO
Beziehungsweise so, falls keine Fehlermeldung erfolgen soll:
create PROCEDURE dbo.sp_test @col1 NVARCHAR(50), @col2 NVARCHAR(50), @col3 NVARCHAR(50), @col4 NVARCHAR(50) AS BEGIN SET NOCOUNT ON
IF not EXISTS (SELECT 1 FROM bulkinsert WHERE (col1 = @col1) and (col3 = @col3) and (col4 = @col4) ) INSERT bulkinsert(col1,col2,col3,col4) VALUES(@col1,@col2,@col3,@col4) END GO
Wobei hier col1, col3 und col4 die Eindeutigkeit eines Datensatzes bilden.
PS: Schade, dass man seine Antwort immer noch nicht editieren kann.
Bei jedem Datensatz zu prüfen, ob er bereits vorhanden ist wäre sehr langsam. Aber ich verstehe das Problem nicht so ganz. Meine Vorgehensweise wäre, einen Index auf die Schlüsselfelder und einen uniqueness constraint zu setzen. Damit ist gewährleistet, dass es keine doppelten Einträge gibt. Du schreibst, dass es bereits einen Index über mehrere Felder gibt. Dann brauchst du den doch nur auf "Is Unique" setzen. Eine Testtabelle, die ich erzeugt habe hat folgenden Index:
CREATE UNIQUE NONCLUSTERED INDEX [IX_bulkinsert] ON [dbo].[bulkinsert] ( [col1] ASC, [col3] ASC, [col4] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO
Damit ist die Eindeutigkeit der Spalten col1, col3, col4 gewährleistet.
Ein UNIQUE Index funktioniert in meinem Fall leider nicht, da durch manuelle Bearbeitungen durchaus doppelte Sätze entstehen dürfen. Nur der Import soll doppelte Sätze vermeiden. Was schon drin ist, soll einfach nicht nochmals rein.
ich denke es fehlen noch ein paar Informationen um Dein Problem "optimal" zu lösen. Soll die SP einen (Massen)Import, wenn ja von wo - interne Tabelle, externe Tabelle, ..., realisieren, oder sollen einzelne Datensätze eigefügt werden?
Möchtest Du eine Universallösung oder kannst Du ein Datenbanksystem festlegen?
insert into tb_destination select * from tb_source where id in ( select s.id from tb_source s ,tb_destination d where d.datum = s.datum and d.personalnummer = s. personalnummer and d.buchungstyp = s.buchungstyp )
Danke der Rückfrage. Nein, es ist kein Massen-Import, eher ständige einzelne INSERTs. Es laufen verschiedene Programme und Windows-Services, die u.a. Daten von BDE-Geräten abrufen, und diese dann in die Datenbank beamen sollen. Mal ist es ein einzelner Satz, mal sind es mehrere hundert. Und wenn jemand eben sein Terminal resettet, dann werden alle Daten nochmals gesendet, auch wenn diese bereits schon mal übertragen worden sind.
Ich bin "Herr über die Datenbank", und kann dort eigentlich alles machen, Datenbank-System ist ein SQL-Server 2005 aufwärts.
Bisher habe ich die Logik mehr schlecht als recht in den Clients, die die INSERTs machen. Da es aber mehrere Programme in verschiedenen Sprachen sind (Web, Windows, Mobil) will ich die Logik weg vom Client in den Server verschieben, eben mittels einer Stored Procedure.