none
Stored Procedure und Rückgabewerte RRS feed

  • Frage

  • Hallo,

    Ich habe eine Tabelle [Sprachen], in welcher als Spalten nur die [Id] und die [Sprache] erfasst werden. Jetzt bin ich dabei eine Gespeicherte Prozedur zu erstellen, über diese sollen neue Sprachen hinzugefügt werden.

    Falls die neu einzufügende Sprache nicht existiert wird eine neue [Sprache] erstellt, auf jeden Fall möchte ich aber diesen neuen Eintrag als Rückgabewert der Prozedur haben. Zusätzlich als Outputparameter die Id übergeben.

    Ziel der Aktion ist es in anderen Prozeduren und auch später über mein C# Programm damit zu arbeiten, also wahlweise nur die [ID] zu verarbeiten und/oder den Tabellendatentyp Sprache im C# Programm.

    Anbei mein Lösungsvorschlag, besonders unsicher bin ich mir bei der letzten Zeile: "SELECT @Id AS ID, @Sprache AS Sprache"

    ALTER PROCEDURE InsertSprachen
    @Sprache NVARCHAR(256)
    , @Id INT OUTPUT
    AS

    BEGIN

    IF EXISTS (SELECT TOP (1) * FROM Sprachen WHERE Sprache = @Sprache) BEGIN SET @Id = @@IDENTITY END ELSE BEGIN INSERT INTO Sprachen([Sprache]) VALUES(@Sprache) SET @Id = SCOPE_IDENTITY() END
    SELECT @Id AS ID, @Sprache AS Sprache

    END


    Dienstag, 21. Oktober 2014 11:42

Antworten

  • Hallo,

    beim erste Fall, wenn die Sprache vorhanden ist, verwendest Du @@IDENTITY, das liefert den zuletzt, in irgendeine Tabelle eingefügte Identity, also hier eher nicht das gewünschte Ergebnis.

    Das SELECT am Ende kannst Du eigentlich einsparen, den der Output Parameter soll ja den Wert liefern, wenn ich Dich richtig verstanden habe. Oder willst Du das Ergebnis immer geliefert werden, z.B. um es von Entity Framework als Objekt zu erhalten?

    Eigentlich reicht es aus, zunächst die ID zu selektieren und wenn das Ergebnis NULL, die Sprache als neue einzufügen:

    REATE TABLE dbo.Sprachen
        (ID int IDENTITY(1, 1) PRIMARY KEY
        ,Sprache NVARCHAR(256));
    GO
    
    
    CREATE PROCEDURE dbo.InsertSprachen
    	  @Sprache	NVARCHAR(256)
    	, @Id		INT OUTPUT
    AS
    BEGIN
        SET NOCOUNT ON;
    
        -- Ermitteln, ob vorhanden
        SET @Id = (SELECT ID FROM dbo.Sprachen WHERE Sprache = @Sprache)
    
        IF @ID IS NULL
    	BEGIN
    		INSERT INTO Sprachen([Sprache]) VALUES(@Sprache)
    		SET @Id = SCOPE_IDENTITY()
    	END
    END
    GO
    
    -- Test:
    DECLARE @ID int;
    
    EXEC dbo.InsertSprachen @Sprache = N'Deutsch', @Id = @ID OUTPUT;
    SELECT @ID;
    
    EXEC dbo.InsertSprachen @Sprache = N'Englisch', @Id = @ID OUTPUT;
    SELECT @ID;
    -- Soll wieder 1 liefern, da bereits vorhanden
    EXEC dbo.InsertSprachen @Sprache = N'Deutsch', @Id = @ID OUTPUT;
    SELECT @ID;


    Olaf Helper

    [ Blog] [ Xing] [ MVP]

    Dienstag, 21. Oktober 2014 11:57
  • Die ursprüngliche Frage war bezüglich einem Output Parameter, den erhältst Du auch in ADO.NET zurück. Die Sprache übergibst Du ja, also sind alle Daten bekannt.

    Aber Du kannst auch wieder Dein ursprüngliches SELECT einbauen, dann kannst Du Dir den OUTPUT Parameter einsparen.


    Olaf Helper

    [ Blog] [ Xing] [ MVP]

    Dienstag, 21. Oktober 2014 12:28

Alle Antworten

  • Hallo,

    beim erste Fall, wenn die Sprache vorhanden ist, verwendest Du @@IDENTITY, das liefert den zuletzt, in irgendeine Tabelle eingefügte Identity, also hier eher nicht das gewünschte Ergebnis.

    Das SELECT am Ende kannst Du eigentlich einsparen, den der Output Parameter soll ja den Wert liefern, wenn ich Dich richtig verstanden habe. Oder willst Du das Ergebnis immer geliefert werden, z.B. um es von Entity Framework als Objekt zu erhalten?

    Eigentlich reicht es aus, zunächst die ID zu selektieren und wenn das Ergebnis NULL, die Sprache als neue einzufügen:

    REATE TABLE dbo.Sprachen
        (ID int IDENTITY(1, 1) PRIMARY KEY
        ,Sprache NVARCHAR(256));
    GO
    
    
    CREATE PROCEDURE dbo.InsertSprachen
    	  @Sprache	NVARCHAR(256)
    	, @Id		INT OUTPUT
    AS
    BEGIN
        SET NOCOUNT ON;
    
        -- Ermitteln, ob vorhanden
        SET @Id = (SELECT ID FROM dbo.Sprachen WHERE Sprache = @Sprache)
    
        IF @ID IS NULL
    	BEGIN
    		INSERT INTO Sprachen([Sprache]) VALUES(@Sprache)
    		SET @Id = SCOPE_IDENTITY()
    	END
    END
    GO
    
    -- Test:
    DECLARE @ID int;
    
    EXEC dbo.InsertSprachen @Sprache = N'Deutsch', @Id = @ID OUTPUT;
    SELECT @ID;
    
    EXEC dbo.InsertSprachen @Sprache = N'Englisch', @Id = @ID OUTPUT;
    SELECT @ID;
    -- Soll wieder 1 liefern, da bereits vorhanden
    EXEC dbo.InsertSprachen @Sprache = N'Deutsch', @Id = @ID OUTPUT;
    SELECT @ID;


    Olaf Helper

    [ Blog] [ Xing] [ MVP]

    Dienstag, 21. Oktober 2014 11:57
  • Hallo Olaf,

    sehr saubere Lösung von dir! Aber was ich noch nicht sehe / verstehe ist: woher kennt später mein C# Programm den Rückgabewert der SP als den Datentyp "Sprachen"?

    Dienstag, 21. Oktober 2014 12:11
  • Die ursprüngliche Frage war bezüglich einem Output Parameter, den erhältst Du auch in ADO.NET zurück. Die Sprache übergibst Du ja, also sind alle Daten bekannt.

    Aber Du kannst auch wieder Dein ursprüngliches SELECT einbauen, dann kannst Du Dir den OUTPUT Parameter einsparen.


    Olaf Helper

    [ Blog] [ Xing] [ MVP]

    Dienstag, 21. Oktober 2014 12:28