2016-03-22 5 views
1

Ich weiß Cursor sind schlecht, aber ich denke, ich habe einen Anwendungsfall, wo sie notwendig sind. Ich habe eine Tabelle (tbl_Items) mit einer Spalte (Item_Code), die ein eindeutiger, zufällig generierter alphanumerischer Code (6 Zeichen) sein soll. Ich habe eine Funktion mit einer Schleife, die einen zufälligen Code erzeugt, prüft, ob sie bereits in der Tabelle existiert und den 6-stelligen Code zurückgibt, sobald er einen unbenutzten Code findet.SQL Cursor Loop Einfrieren ohne Fehler

Neue Datensätze in der Tabelle tbl_Items beginnen mit Item_Code, das NULL ist. Ich muss ein UPDATE für alle diese neuen Datensätze ausführen und den Item_Code auf den Rückgabewert der Funktion festlegen. Ich kann natürlich nicht alles mit einer einzigen UPDATE-Anweisung tun, da die Funktion nicht in der Lage ist, den Item_Code jeder neuen Zeile auf Eindeutigkeit zu prüfen, bis die gesamte Transaktion abgeschlossen ist.

Also der CURSOR. Hier ist, was ich gerade habe:

Ich habe die Druckzeile hinzugefügt, nur um zu sehen, was vor sich ging. Ich bekomme ständig 10 erfolgreich aktualisierte Zeilen, dann stoppt es einfach komplett. Kein Fehler oder irgendetwas, es bleibt nur "Executing ...", aber die Tabelle tbl_Items wird nicht mehr aktualisiert, und nichts anderes wird im Nachrichtenfenster ausgegeben.

Kann mir hier jemand in die richtige Richtung zeigen? Es gibt ungefähr 40.000 Datensätze in der ersten Abfrage für den CURSOR. Vielen Dank!

UPDATE: Hier ist die Funktion, die den eindeutigen 5-stelligen Code (5, nicht 6) zurückgibt. „Random_view“ ist eine Ansicht, die nur eine einzige Spalte, die ein Zufallswert zwischen 0 und 1.

CREATE FUNCTION [dbo].[generate_unique_code] 
(
    @ItemId bigint 
) 
RETURNS varchar(5) 
AS 
BEGIN 
    DECLARE @Length int 
    DECLARE @CharPool varchar(36) 
    DECLARE @PoolLength int 
    DECLARE @LoopCount int 
    DECLARE @RandomString varchar(5) 
    DECLARE @RandomInt decimal(18,18) 
    DECLARE @IsUnique bit 
    DECLARE @CodeExists bigint = NULL 

    SET @Length = 6 
    SET @CharPool = 'abcdefghijklmnopqrstuvwxyz' 
    SET @PoolLength = Len(@CharPool) 

    SET @LoopCount = 0 
    SET @RandomString = '' 
    SET @IsUnique = 0 

    WHILE (@IsUnique = 0) BEGIN 
     -- GENERATE UNIQUE 5 CHARACTER STRING 
     WHILE (@LoopCount < @Length) BEGIN 
      SELECT @RandomInt = rnd 
      FROM random_view 
      SELECT @RandomString = @RandomString + SUBSTRING(@Charpool, CONVERT(int, @RandomInt * @PoolLength), 1) 
      SELECT @LoopCount = @LoopCount + 1 
     END 
     -- CHECK IF CODE ALREADY EXISTS IN THE DATABASE 
     SELECT @CodeExists = Item_ID 
     FROM tbl_Items 
     WHERE Item_Code = LEFT(@RandomString,5) 

     -- IF CODE IS NOT ALREADY IN THE DATABASE, BREAK LOOP TO USE IT 
     IF @CodeExists IS NULL BEGIN 
      SET @IsUnique = 1 
     END 
    END 

    RETURN LEFT(@RandomString,5) 
END 
+0

Für welches RDBMS ist das? Bitte fügen Sie ein Tag hinzu, um anzugeben, ob Sie 'mysql',' postgresql', 'sql-server',' oracle' oder 'db2' verwenden - oder etwas ganz anderes. –

+0

Was @marc_s sagte plus 'Neue Datensätze in der tbl_Items-Tabelle beginnen mit Item_Code ist NULL' - bedeutet das, dass die Daten bereits da sind, oder fügen Sie Zeilen mit diesem NULL-Wert ein? – cantSleepNow

+0

Entschuldigung, ich habe gerade das sql-server-Tag hinzugefügt. Und ja, die Datensätze werden mit dem NULL-Wert eingefügt. Ich habe ein SSIS-Paket, das eine wöchentliche BULK INSERT von einer CSV-Datei zu einer Staging-Tabelle, dann ein MERGE in die Produktionstabelle zum Einfügen/Aktualisieren von Datensätzen. – ItJustWerks

Antwort

1

Es gibt ein Problem mit der Funktion ist. Es wird in Endlosschleife laufen. Da Sie den Wert LoopCount nach dem Verlassen der inneren while-Schleife nicht auf 0 zurücksetzen, wird die innere while-Schleife nur einmal ausgeführt. Es bedeutet, dass, wenn Sie im ersten Lauf keinen eindeutigen Code erhalten, die äußere while-Schleife unendlich weiterläuft, und ich denke, dass das passiert, da es keinen eindeutigen Code finden kann. Wenn Sie nur zufällige eindeutige Codes generieren möchten, können Sie Folgendes tun: SELECT @randomString = CONVERT(varchar(255), NEWID()). Sie müssen nur die Länge von Item_Code erhöhen.

+0

Dies ist eine großartige Antwort. Und ich habe tatsächlich am Ende die Zufallsgenerator-Funktion reduziert, um SELECT @new_code = LEFT (NEWID(), 5) zu verwenden – ItJustWerks