Insert Into aus Select Key hochzählen

Scarry

Neuer Benutzer
Beiträge
4
Hallo Zusammen,

ich hoffe mir kann jemand helfen. Bin auch nach längerer Suche nicht schlauer geworden.

DB: MSSQL

Ziel:
Eine Adressliste soll regelmäßig aus einer CSV Datei in eine bestehende Datenbank mit Adressdaten importiert werden.
Einige Adressen kann es schon geben, diese werden dann nur aktualisiert und alle anderen werden importiert.

Problem ist die Vergabe des Keys.

Ich bin bisher wie folgt vorgegangen.
1. Anlage temp Tabelle mit den Feldern der csv Datei.
2. Bulk Insert aus der csv Datei
3. Insert Into aus der temp Tabelle zur Adresstabelle
Hier soll er jedoch anhand der bestehenden Adressnummer neue Adressnummern fortlaufend vergeben.
Mit MAX()+1 geht das super wenn ich nur einen Datensatz habe, aber sobald es mehrere sind funktioniert es nicht mehr.

Hier mal sehr abgespeckt nur mit den benötigten Feldern

CREATE TABLE temp_Adressen (
Matchcode VARCHAR(50)
);

BULK INSERT temp_Adressen
FROM 'C:\Test.csv'
WITH ( CODEPAGE = 'RAW', FIRSTROW = 2,
FIELDTERMINATOR = ';',
ROWTERMINATOR = '\n');

INSERT INTO Adressen (Adresse, Matchcode)
SELECT (SELECT MAX(Adressen.Adresse)+1 FROM Adressen), temp_Adressen.Matchcode FROM temp_Adressen WHERE temp_Adressen.Matchcode NOT IN (SELECT Adressen.Matchcode FROM Adressen);


Hat jemand eine Idee, wie die Vergabe des Keys ordentlich funktioniert?

Vielen Dank im Voraus

Scarry
 
Werbung:

dabadepdu

Datenbank-Guru
Beiträge
953
Kann es sein, dass Du ein Problem lösen möchtest, das es nicht gibt?
Normalerweise würde die "Adressnummer" wohl automatisch über autoincrement generiert.
Wie sieht die Tabellen- / Triggerdefinition von Adressen aus?
Was geschieht, wenn Du einen minimalen Datensatz einfügst- ohne das Feld Adressnummer anzugeben - und mit?
 

Scarry

Neuer Benutzer
Beiträge
4
Leider ist es kein autoincrement Feld.
Wenn ich beim Einfügen das Feld Adressnummer leer lasse, kommt die Meldung, dass es bereits einen Datensatz mit dem Schlüssel 0 gibt.
 

dabadepdu

Datenbank-Guru
Beiträge
953
Das geht leider nicht, ist ein fertiges Programm, dass diese Datenbank nutzt.
Das klingt etwas danach, dass Du das gar nicht machen solltest, was Du da machst. Gewährleistung, Datenintegrität usw. sind immer ein Thema, wenn man in einem anderem Programm "rumwerkelt", es sei denn es ist ein totes Hausgewächs.

Du könntest die max ID einmalig bestimmen und dann programmatisch hochzählen und vergeben. Könnte gehen, wenn alles eine Transaktion ist (also Bestimmung Max ID plus gesamter Insert) und wenn Du das auf Randeffekte prüfst, die im regulären und im Mischbetrieb mit Deinem Code auftreten. Dabei können Dir Effekte des Bulkinsert (parallel processing), Trigger usw. in die Hacken laufen. Also nicht unbedingt in einem produktiven System testen.
 

Tommi

Datenbank-Guru
Beiträge
286
Hallo Scarry,

das ist ein eigentlich recht leicht lösbares Problem, da die Darstellung deiner Vorbereitung nur wenig Anpassungen benötigt.
Da du für den Bulk-Insert erst einmal eine Staging-Tabelle erstellst und diese dann füllst, kannst du in dieser Tabelle einfach ein Autowert-Feld hinzufügen.

Der Bulk-Insert kann mit einem Autowert-Feld Ärger machen, wenn dieses Feld nicht in der CSV-Datei enthalten oder vorgesehen ist. Von diesem Sachverhalt gehe ich mal aus.
Das ist aber kein großes Problem, dann kannst du nämlich die Autowert-Spalte einfach nach dem einlesen in der temporären Tabelle hinzufügen.
Dein bisheriger CREATE bleibt dann also unverändert und du setzt nach dem Einlesen folgenden Befehl ab:

Code:
ALTER TABLE temp_Adressen
ADD ID int IDENTITY(1,1)

Die gefüllte Autowert-Spalte befindet sich dann am Ende der temporären Tabelle, Start der ID ist die 1.

Im nächsten Schritt überträgst du ja dann die Werte aus der temporären Tabelle in die eigentliche Ziel-Tabelle.
Aus der Ziel-Tabelle liest du den maximalen bereits vergebenen ID-Wert aus und schreibst diesen in eine Variable:

Code:
DECLARE @MaxID int
SELECT @MaxID = MAX(ID) FROM Adressen.Adresse

Der Wert dieser Variablen wird dann beim INSERT in die Zieladresse einfach auch den Wert der Spalte ID in der temporären Tabelle addiert und in die ID-Spalte der Zieltabelle geschrieben.


Bei SQL Server ab Version 2017 gibt es für den BULK INSERT die Möglichkeit eine Format-Datei für eine Quelldatei wie CSV anzugeben.
In dieser wird dann das einzulesende Format der Spalten aus der Quelle vorgegeben.
Das würde aber mehr Aufwand erfordern, als ich grade beschrieben habe.
Genauere Informationen zu dem Thema mit IDs und dem BULK INSERT gibt es hier:
BULK INSERT (Transact-SQL) - SQL Server | Microsoft Docs

Interessante Punkte auf dieser Seite sind
FORMATFILE_DATA_SOURCE
KEEPIDENTITY (hier wird auch beschrieben, wie das Verhalten des BULK INSERT bei einer bestehenden Autowert-Spalte ist)


Viele Grüße,
Tommi
 

dabadepdu

Datenbank-Guru
Beiträge
953
Der Wert dieser Variablen wird dann beim INSERT in die Zieladresse einfach auch den Wert der Spalte ID in der temporären Tabelle addiert und in die ID-Spalte der Zieltabelle geschrieben.
Ja, einfach, nur nicht unbedingt für parallele Nutzung geeignet. Wie schon geschrieben, müsste das in einer Transaktion laufen.
 

Scarry

Neuer Benutzer
Beiträge
4
Vielen Dank Tommi. Habe es jetzt so ähnlich gelöst. Die Formatierungsmöglichkeiten schau ich mir mal noch an :)

dabedepdu - du hast nicht unrecht, parallele Nutzung soll auch verhindert werden. Also das dies nur außerhalb vom Echtbetrieb läuft.
 
Werbung:
Oben