Reputation: 3555
I am a beginner with SQL and especially with TSQL. I need to write a SP for SQL Server 2008 that will read all records that match some criteria and then read in different result sets their associated category, ingredients, units and so on. For reading one element my SP is:
-- Select the recipe
SELECT Recipe.*
FROM Recipe
WHERE Recipe.RecipeId = @RecipeId
-- Select the categories themselves
SELECT Category.*
FROM Category
JOIN RecipeCategory ON RecipeCategory.CategoryId = Category.CategoryId
WHERE RecipeCategory.RecipeId = @RecipeId
-- Select the ingredient information for the recipe
SELECT RecipeIngredient.*
FROM RecipeIngredient
JOIN Recipe ON Recipe.RecipeId = RecipeIngredient.RecipeId
WHERE Recipe.RecipeId = @RecipeId
-- Select the ingredients themselves
SELECT Ingredient.*
FROM Ingredient
JOIN RecipeIngredient ON RecipeIngredient.IngredientId = Ingredient.IngredientId
JOIN Recipe ON Recipe.RecipeId = RecipeIngredient.RecipeId
WHERE Recipe.RecipeId = @RecipeId
-- Select the units that are associated with the ingredients
SELECT Unit.*
FROM Unit
JOIN Ingredient ON Ingredient.UnitId = Unit.UnitId
JOIN RecipeIngredient ON RecipeIngredient.IngredientId = Ingredient.IngredientId
WHERE RecipeIngredient.RecipeId = @RecipeId
How can I transform it to read all recipes that have Name like '%..%'
Since the table has millions of recipes I would like to do it as efficient as possible.
Upvotes: 1
Views: 858
Reputation: 15251
For selecting recipes by Name (with wildcards), you might alter your proc to do something like this:
-- Get a list of name-matched RecipeIDs
DECLARE @RecipeIDs TABLE (
RecipeID int not null primary key
)
INSERT INTO @RecipeIDs (RecipeID)
SELECT Recipe.RecipeID
FROM Recipe
-- Change the parameter of the proc from @RecipeId to @Name
WHERE Recipe.Name like '%' + @Name + '%'
-- Select the recipes
SELECT Recipe.*
FROM Recipe
WHERE Recipe.RecipeId in (select RecipeID from @RecipeIDs)
-- Select the categories themselves
SELECT Category.*
FROM Category
JOIN RecipeCategory ON RecipeCategory.CategoryId = Category.CategoryId
WHERE RecipeCategory.RecipeId in (select RecipeID from @RecipeIDs)
-- Select the ingredient information for the recipes
SELECT RecipeIngredient.*
FROM RecipeIngredient
JOIN Recipe ON Recipe.RecipeId = RecipeIngredient.RecipeId
WHERE Recipe.RecipeId in (select RecipeID from @RecipeIDs)
-- Select the ingredients themselves
SELECT Ingredient.*
FROM Ingredient
JOIN RecipeIngredient ON RecipeIngredient.IngredientId = Ingredient.IngredientId
JOIN Recipe ON Recipe.RecipeId = RecipeIngredient.RecipeId
WHERE Recipe.RecipeId in (select RecipeID from @RecipeIDs)
-- Select the units that are associated with the ingredients
SELECT Unit.*
FROM Unit
JOIN Ingredient ON Ingredient.UnitId = Unit.UnitId
JOIN RecipeIngredient ON RecipeIngredient.IngredientId = Ingredient.IngredientId
WHERE RecipeIngredient.RecipeId in (select RecipeID from @RecipeIDs)
I'm first getting all of the recipe IDs that match a new @Name parameter, then getting your result sets using IN
instead of =
.
As far as performance, be sure you're getting the correct results first before trying to optimize for speed. However, if you have a performance problem, there are some other ways to write the query. For example, if the list of matched IDs gets huge, you might rather use temp table instead of a table variable to keep the list, or just in-line the name-matching part into every select individually. Maybe a join on the RecipeIDs would be faster than the IN
. Of course, the SQL engine may do very much the same thing in all of those cases (SQL is essentially declarative, after all). Indexing of the tables could come into play as well. Please let us know how this works out for you.
Upvotes: 1