在SQL中,选择一对多表中的所有FK,其中FK的表数据存在于多个列表/联接中
我的数据库中有带关联数据的配方(在一系列类别中,每个配方都有[0-多个]选项供每个类别选择)。要搜索食谱,用户可以从[0-多]类别中选择[0-多]选项 我试图构造一个存储过程,返回所有RecipeID,这些RecipeID至少与用户至少选择一个OptionID的每个类别的OptionID匹配 因此-如果您想找到所有主菜和水果甜点,proc需要返回所有RecipeID,其中:在SQL中,选择一对多表中的所有FK,其中FK的表数据存在于多个列表/联接中,sql,stored-procedures,Sql,Stored Procedures,我的数据库中有带关联数据的配方(在一系列类别中,每个配方都有[0-多个]选项供每个类别选择)。要搜索食谱,用户可以从[0-多]类别中选择[0-多]选项 我试图构造一个存储过程,返回所有RecipeID,这些RecipeID至少与用户至少选择一个OptionID的每个类别的OptionID匹配 因此-如果您想找到所有主菜和水果甜点,proc需要返回所有RecipeID,其中: 在RecipeData中,对于具有相同RecipeID的所有条目(对于单个配方的所有选项) 至少有一个OptionID
- 在RecipeData中,对于具有相同RecipeID的所有条目(对于单个配方的所有选项)
- 至少有一个OptionID用于“主菜”或至少有一个OptionID用于“甜点”
- 至少有一个选项ID是“水果”
- 并忽略“排名”(用户未在此类别中选择任何选项)
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)
表:
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
我的解决方案:
-- @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
我的解决方案:
-- @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