I am trying to create a stored procedure to which is passed a TVP and then some data from the TVP is inserted into two tables.
I have already implemented the stored procedure, but only the second insert (the only one that does not read from the TVP) is working. The other two are not working (do not insert anything) and I can’t seem to figure out why.
I have tried to create a dummy TVP in SQL Server and run the procedure there, but that also did not work. Is this being caused by the fact TVPs are readonly? I would assume not, since I am not actually inserting or updating data inside the TVP.
Is there a way to make this work?
Thank you for your assistance!
Table-valued parameter definition:
CREATE TYPE dbo.Ingredients AS TABLE ( Quantity int, Measure nvarchar(50), Ingredient nvarchar(50), ) GO
Stored procedure:
ALTER PROCEDURE uspCreateRecipe (@IDUser int, @RecipeName nvarchar(50), @Category nvarchar(50), @Difficulty nvarchar(50), @Duration nvarchar(50), @ING dbo.Ingredients READONLY, @Execution text) AS BEGIN INSERT INTO dbo.Ingredients VALUES ((SELECT Ingredient FROM @ING WHERE NOT EXISTS (SELECT Ingredient FROM @ING WHERE Ingredient IN (SELECT IngredientName FROM dbo.Ingredients))), 2) INSERT INTO dbo.Recipes VALUES (@IDUser, @RecipeName, NULL, (SELECT IDDifficulty FROM dbo.Difficulty WHERE Difficulty = @Difficulty), (SELECT IDDuration FROM dbo.Duration WHERE Duration = @Duration ), NULL, (SELECT IDCategory FROM dbo.Category WHERE CategoryName = @Category ), @Execution , NULL, 2, GETDATE()) INSERT INTO dbo.Recipes_Ingredients VALUES (SCOPE_IDENTITY(), (SELECT Quantity FROM @ING), (SELECT IDMeasure FROM dbo.Measure WHERE Measure IN (SELECT Measure FROM @ING)), (SELECT IDIngredient FROM dbo.Ingredients WHERE IngredientName IN (SELECT Ingredient FROM @ING))) END
Advertisement
Answer
- Rather than using
VALUES
with sub-queries, just useSELECT
. - Always list the columns you are inserting into. Its clearer and will reduce errors especially if you modify the table structure in future,
- Your first query appeared to be overcomplicated – if indeed it worked at all.
- Your third query should have thrown an error because you have multiple
IN
sub-queries which should have resulted in a “sub-query returned multiple results” error. - The
text
datatype is depreciated usevarchar(max)
. - Normally you want to
SET NOCOUNT, XACT_ABORT ON
. - Always
RETURN
a status so your calling app knows whether it succeeded or not. 0 will be returned by default by I prefer to be explicit. - Semi-colon terminate all statements.
ALTER PROCEDURE uspCreateRecipe ( @IDUser int , @RecipeName nvarchar(50) , @Category nvarchar(50) , @Difficulty nvarchar(50) , @Duration nvarchar(50) , @ING dbo.Ingredients READONLY , @Execution nvarchar(max) -- text is depreciated ) AS BEGIN SET NOCOUNT, XACT_ABORT ON; INSERT INTO dbo.Ingredients ([Name], Col2) SELECT Ingredient, 2 FROM @ING WHERE Ingredient NOT IN (SELECT IngredientName FROM dbo.Ingredients); INSERT INTO dbo.Recipes (IDUser, RecipeName, Col3, IDDifficulty, IDDuration, Col6, IDCategory, Col8, Col9, Col10, Co11) SELECT @IDUser, @RecipeName, NULL, IDDifficulty , (SELECT IDDuration FROM dbo.Duration WHERE Duration = @Duration) , NULL , (SELECT IDCategory FROM dbo.Category WHERE CategoryName = @Category) , @Execution, NULL, 2, GETDATE() FROM dbo.Difficulty WHERE Difficulty = @Difficulty; INSERT INTO dbo.Recipes_Ingredients (IDRecipe, Quantity, IDMeasureid, IDIngredient) SELECT SCOPE_IDENTITY(), Quantity , (SELECT IDMeasure FROM dbo.Measure WHERE Measure = I.Measure) , (SELECT IDIngredient FROM dbo.Ingredients WHERE IngredientName = I.Ingredient) FROM @ING I; RETURN 0; END;