Laden...

Wie per SQL neue Artikelnummer generieren?

Erstellt von mikefried vor 10 Jahren Letzter Beitrag vor 10 Jahren 3.992 Views
M
mikefried Themenstarter:in
198 Beiträge seit 2010
vor 10 Jahren
Wie per SQL neue Artikelnummer generieren?

verwendetes Datenbanksystem: SQL Server 2012

Hallo an Alle!

Ich muss für mein Programm neue Artikelnummern generieren. Dazu habe ich mir eine
einfache SQl Prozedur geschrieben:


DECLARE @LetzteVGnummer  int;

  Select  @LetzteVGnummer =  MAX(CAST(TMP.NeueArtikelnummer as int))  
                 FROM (
                     Select SUBSTRING(ART.Artikelnummer, 4, 7)  as NeueArtikelnummer 
                     FROM ART                    
                     WHERE ART.Artikelnummer LIKE 'VG#%'
					 ) as TMP 
                 Where  ISNUMERIC(TMP.NeueArtikelnummer) = 1     


 INSERT INTO  dbo.ART 
		(
		   [Artikelnummer]	
		   ,[Bezeichnung]	
		   ,[LosgroesseVerkauf]
		)
		VALUES
		(
		     N'VG#' + CAST((@LetzteVGnummer + 1) AS nvarchar(80))
			 ,N'DBGen'		
			,0
		)

RETURN SCOPE_IDENTITY()


Wie im SQL code zu sehen ist, wird gleich ein neuer Artikel angelegt. Die Artikelnummer muss eineindeutig sein. Anschließend wird die Identität zurückgegeben.
Das funktioniert auch alles sehr gut!

Nuuur...

Nun habe ich mein Programm veröffentlicht und es arbeiten viele Leute parallet auf der DB. Wird meine Prozedur aufgerufen kommt sehr oft die Fehlermeldung:

Eine Zeile mit doppeltem Schlüssel kann in das dbo.ART-Objekt mit dem eindeutigen PRIMARY-Index nicht eingefügt werden

Hier brauche ich eine eine Lösung.

Ich weiss nicht ob irgendwo in der DB eingestellt ist, das das INSERT eine weiteres INSERT blockiert. Oder muss ich ein paralleles INSERT verhindern.

Für einen Tipp wäre ich sehr dankbar.

Mike

16.833 Beiträge seit 2008
vor 10 Jahren

Deine Artikelnummer hat einen Prefix: wieso hälst Du den Präfix in der DB und nicht im Repository (DB-Abstraktionsschicht) in der Applikation?
Dahingehend könntest Du mit einem Int-Schlüssel arbeiten, der als Key und AutoIncrement definiert ist. Ergo: macht den Umgang einfacher und ist nicht so Fehleranfällig.

Ansonsten kannst Du eben ID (KeyFeld) und Artikelnummer trennen, wobei die ID anschließend die Artikelnummer mit führenden Nullen darstellt:
ID | Artikelnummer | Bezeichnung | LosgroesseVerkauf

CREATE PROCEDURE InsertArticle
 @Bezeichnung VARCHAR(MAX),
 @LosGroesseVerkauf INT
AS
BEGIN
 DECLARE @NewArticleID VARCHAR(15);
 DECLARE @Prefix VARCHAR(10) = 'VG#';
 DECLARE @Id INT;

SELECT @Id = ISNULL(MAX(ID),0) + 1 FROM ART

 SELECT @NewArticleID = @Prefix + RIGHT('0000000' + CAST(@Id AS VARCHAR(7)), 7)

INSERT INTO ART VALUES (@Id,@NewArticleID,@Bezeichnung,@LosGroesseVerkauf)
END
L
416 Beiträge seit 2008
vor 10 Jahren

@Abt: Dein Vorschlag verhindert zwar doppelte uneindeutige Einträge aber führt doch letztendlich zu Artikeln mit gleicher Artikelnummer? (Oder werden Procedures isoliert ausgeführt?)

Das Ganze in eine Transaktion zu packen würd ich denken wär hier zielführend.
Oder die Artikelnummer als Computed Column aus Prafix und ID.

16.833 Beiträge seit 2008
vor 10 Jahren

Die Artikelnummer ergibt sich aus der ID. Da es keine doppelte ID geben kann, gibt es auch keine doppelten Artikelnummern.

L
416 Beiträge seit 2008
vor 10 Jahren

Klar gibts keine doppelten IDs aber was verhindert das die Procedure gleichzeitig läuft und die gleiche "alte" ID ausliest und mit +1 in die Artikelbezeichnung schreibt? Ist doch im Prinzip der gleiche Ablauf wie mikefried ihn hatte nur über ein extra Feld.

M
mikefried Themenstarter:in
198 Beiträge seit 2010
vor 10 Jahren

Wie geht das mit ner Transaktion?

Das habe ich noch nie gemacht.

M
mikefried Themenstarter:in
198 Beiträge seit 2010
vor 10 Jahren

Die Transaktion macht doch nur einen ROLLBACK?

Da habe ich doch noch keine neue Artikelnummer?

M
171 Beiträge seit 2012
vor 10 Jahren

Ich glaube der Hinweis, der hier entscheidender ist, ist der von Abt, mit einem Int-Schlüssel + AutoIncrement zu arbeiten. Dann kannst Du Dir die Procedure komplett sparen.

M
mikefried Themenstarter:in
198 Beiträge seit 2010
vor 10 Jahren

da bin ich mir nicht sicher!

Die neue ID per AutoIncrement bekomme ich ja nur, wenn ich eine neue Artikelnummer
mit angebe und dann ein INSERT mache

An der Tabelle/Spalten kann ich auch nichts ändern

16.833 Beiträge seit 2008
vor 10 Jahren

Klar gibts keine doppelten IDs aber was verhindert das die Procedure gleichzeitig läuft und die gleiche "alte" ID ausliest und mit +1 in die Artikelbezeichnung schreibt?

Mhh....

da bin ich mir nicht sicher!

Ich aber.
Variante 1 von mir war, dass Du nur mit ID (AutoIncrement/Unique/Key) und Bezeichnung arbeitest
Das Format erfolgt dann ausschließlich im Repository.

Sprich die DB kennt nur den INT-Wert, der garantiert einmalig ist (ab Insert). Un der DB-Schicht der Anwendung formst Du das ganze dann zB mit Prefix und mit 9 Stellen.

L
416 Beiträge seit 2008
vor 10 Jahren

An der Tabelle/Spalten kann ich auch nichts ändern

Heißt das du kannst an der Tatsache das Artikelnummer PK ist gar nichts ändern, also auch keinen neuen PK einfügen?
Dann bleibt dir mE nach ja nur die Möglichkeit mit Transaktionen zu arbeiten. Dazu dann bitte selbst in das Thema einlesen und nicht irgendwelche Spekulationen hier abgeben. Gibt dazu mehr als genung Infos im Netz.

Mhh....

Meine Einwände waren eig nur auf den Procedure-Vorschlag bezogen. Prinzipiell finde ich den Vorschlag über eine ID auf Anwendungsebene die Artikelbezeichnung zu generieren auch am besten. Falls mikefried dazu die Möglichkeit hat.

M
mikefried Themenstarter:in
198 Beiträge seit 2010
vor 10 Jahren

Was für Spekulationen ?

W
955 Beiträge seit 2010
vor 10 Jahren

Man könnte das auch per Sequence lösen.

L
416 Beiträge seit 2008
vor 10 Jahren

Was für Spekulationen ?

Die Transaktion macht doch nur einen ROLLBACK?

Ich bin aber jetzt raus hier, wenn du scheinbar keine Lust hast uns die relevanten Informationen zu geben.

3.511 Beiträge seit 2005
vor 10 Jahren

witte hat es ja schon gepostet. Wenn du SQL 2012 verwendest, dann nimm Sequences. Die Dinger sind ACID.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

129 Beiträge seit 2007
vor 10 Jahren

Nun ja ich würde ja eher dazu tendieren auf die GTIN ehemals EAN zu setzen und diese dann jeweil händisch eintragen, denn auch diese Nummern sind eindeutig.
Zumal ja wie du schreibst auch Personen mit dem Programm arbeiten.
Der Vorteil anhand der GTIN (Global Trade Item Number) liegt daran das diese zum einen auf jedem Artikel vorhanden sein sollten und zum anderen die Nummer auch authentisch zum Artikel wäre.

So würde ich es jedenfalls machen wenn Personen mit der Software auch arbeiten sollen. 😁

C
2.121 Beiträge seit 2010
vor 10 Jahren

Zunächst mal, um die Statements muss wirklich eine Transaktion herum, um paralleles ausführen zu verhindern. Soviel ist klar.

Ich halte es aber trotzdem für unwahrscheinlich dass die Prozedur oft parallel aufgerufen wird. Zumindest falls sie nicht lange aktiv ist, ich weiß ja nicht wie das Subselect sich verhält.
Interessehalber würde ich protokollieren was ein Aufruf der Prozedur für eine ID erzeugt. Dann siehst du bei der nächsten Fehlermeldung was da wirklich passiert. Vielleicht stimmt ja noch was ganz anderes nicht.

M
mikefried Themenstarter:in
198 Beiträge seit 2010
vor 10 Jahren

Vielen Dank für die Info's !

Mike