[英]In SQL, Select all FKs from one-to-many table where table data for FK Exists in each of several lists/joins
My database has recipes with associated data (within a range of categories, each recipe has [0 - many] options selected for each category).我的数据库有带有关联数据的食谱(在一系列类别中,每个食谱都有为每个类别选择的 [0 - 许多] 选项)。 To search the recipes, a user can select [0 - many] options from [0 - many] categories.要搜索食谱,用户可以 select [0 - 许多] 类别中的 [0 - 许多] 选项。
I'm trying to construct a stored procedure that returns all RecipeIDs that match at least one OptionID for each Category where the user selected at least one OptionID.我正在尝试构建一个存储过程,该过程返回与用户选择至少一个 OptionID 的每个类别的至少一个 OptionID 匹配的所有 RecipeID。
So - if you want to find all main dishes and desserts with fruit, the proc needs to return all RecipeIDs where:所以 - 如果您想找到所有主菜和带水果的甜点,proc 需要返回所有 RecipeIDs,其中:
The number of Categories is finite and limited (currently 12).类别的数量是有限的(目前是 12 个)。 Right now, I have the user's search query supplied as 12 table variables - one for each Category, listing the selected OptionIDs for that Category.现在,我将用户的搜索查询作为 12 个表变量提供 - 每个类别一个,列出该类别的选定 OptionID。 I'd prefer to submit the user's search query to the proc as a single table, but I'm not sure if that would be possible.我更愿意将用户的搜索查询作为单个表提交给 proc,但我不确定这是否可行。 Regardless, that's a lower priority.无论如何,这是一个较低的优先级。
It must be possible to construct a query to return what I'm looking for, but I have no idea how to do this.必须可以构造一个查询来返回我正在寻找的内容,但我不知道该怎么做。 Everything I can think of involves looping through groups (RecipeData for each Recipe, Options for each Category), and from what I know, SQL isn't built to do this.我能想到的一切都涉及循环组(每个食谱的 RecipeData,每个类别的选项),据我所知,SQL 不是为此而构建的。
Can I do this in SQL, or will I have to do this in my C# code?我可以在 SQL 中执行此操作,还是必须在我的 C# 代码中执行此操作? If I can do this in SQL - how?如果我可以在 SQL 中做到这一点 - 怎么做?
Parameters:参数:
DECLARE @MealTypeOptionID TABLE ( OptionID INT )
DECLARE @IngredientOptionID TABLE ( OptionID INT )
DECLARE @RankingOptionID TABLE ( OptionID INT )
-- all 'Main Dish' or 'Dessert' recipes that have 'Fruit'
INSERT INTO @MealTypeOptionID (OptionID) VALUES (1), (2)
INSERT INTO @IngredientOptionID (OptionID) VALUES (4)
Tables:表:
Recipe
---------------------------------------------------------------
RecipeID RecipeName
---------------------------------------------------------------
1 'Apple Pie'
2 'Blueberry Ice Cream'
3 'Brownies'
4 'Tuna Casserole'
5 'Pork with Apples'
6 'Fruit Salad'
Category
---------------------------------------------------------------
CategoryID CategoryName
---------------------------------------------------------------
1 'Meal Type'
2 'Ingredients'
3 'Ranking'
Option
---------------------------------------------------------------
OptionID CategoryID OptionName
---------------------------------------------------------------
1 1 'Main Dish'
2 1 'Dessert'
3 1 'Side Dish'
4 2 'Fruit'
5 2 'Meat'
6 3 'Meh'
7 3 'Great'
RecipeData
---------------------------------------------------------------
RecipeDataID RecipeID OptionID
---------------------------------------------------------------
1 1 2
2 1 4
3 1 7
4 2 2
5 2 4
6 3 2
7 4 1
8 4 5
9 4 6
10 5 1
11 5 4
12 5 5
13 6 3
14 6 4
My solution:我的解决方案:
-- @optionsToInclude is a parameter of the proc
DECLARE @optionsToInclude TABLE (CategoryID INT, OptionID INT)
-- result table
DECLARE @recipeIDs TABLE (RecipeID INT)
-- get CategoryID FOR first select
DECLARE @categoryID INT
SELECT TOP 1 @categoryID = CategoryID FROM @optionsToInclude GROUP BY CategoryID
-- insert into result table all RecipeIDs that contain any OptionIDs within CategoryID
INSERT INTO @recipeIDs (RecipeID)
SELECT DISTINCT d.RecipeID
FROM RecipeData d
INNER JOIN @optionsToInclude c
ON c.CategoryID = @categoryID
AND c.OptionID = d.OptionID
-- delete from @optionsToInclude all entries where CategoryID = @categoryID
DELETE FROM @optionsToInclude WHERE CategoryID = @categoryID
-- check if any more Categories exist to loop through
DECLARE @exists BIT = 1
IF (NOT EXISTS (SELECT * FROM @optionsToInclude))
SET @exists = 0
WHILE @exists = 1
BEGIN
-- get CategoryID for select
SELECT TOP 1 @categoryID = CategoryID FROM @optionsToInclude GROUP BY CategoryID
-- delete from result table all RecipeIDs that do not contain any OptionIDs within CategoryID
DELETE FROM @recipeIDs
WHERE RecipeID NOT IN
(
SELECT DISTINCT d.RecipeID
FROM dbo.RecipeData d
INNER JOIN @optionsToInclude i
ON i.CategoryID = @categoryID
AND i.OptionID = d.OptionID
)
-- delete from @optionsToInclude all entries where CategoryID = @categoryID
DELETE FROM @optionsToInclude WHERE CategoryID = @categoryID
-- check if any more Categories exist to loop through
IF (NOT EXISTS (SELECT * FROM @optionsToInclude))
SET @exists = 0
END
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.