2

我有 3 张桌子:

  • 食谱:
    • 身份证,姓名
  • 成分:
    • 身份证,姓名
  • 配方成分:
    • id、recipeId、componentId、数量

每次,客户创建一个新配方时,我都需要检查recipeingredient表格以验证该配方是否存在。如果ingredientIdquantity完全相同,我会告诉客户配方已经存在。由于我需要检查多行,因此需要帮助来编写此查询。

4

3 回答 3

2

了解您的成分和数量后,您可以执行以下操作:

select recipeId as ExistingRecipeID
from recipeingredient
where (ingredientId = 1 and quantity = 1)
    or (ingredientId = 8 and quantity = 1)
    or (ingredientId = 13 and quantity = 1)
group by recipeId
having count(*) = 3 --must match # of ingeredients in WHERE clause
于 2012-09-25T14:54:12.077 回答
2

我最初认为以下查询会找到具有完全相同成分的食谱对:

select ri1.recipeId, ri2.recipeId
from RecipeIngredient ri1 full outer join
     RecipeIngredient ri2
     on ri1.ingredientId = ri2.ingredientId and
        ri1.quantity = ri2.quantity and
        ri1.recipeId < ri2.recipeId
group by ri1.recipeId, ri2.recipeId
having count(ri1.id) = count(ri2.id) and   -- same number of ingredients
       count(ri1.id) = count(*) and        -- all r1 ingredients are present
       count(*) = count(ri2.id)            -- all r2 ingredents are present

但是,此查询无法正确计算事物,因为不匹配项没有正确的 id 对。唉。

以下确实进行了正确的比较。它在连接之前计算每个配方中的成分,因此可以在所有匹配的行上比较这个值。

select ri1.recipeId, ri2.recipeId
from (select ri.*, COUNT(*) over (partition by recipeid) as numingredients
      from @RecipeIngredient ri
     ) ri1 full outer join
     (select ri.*, COUNT(*) over (partition by recipeid) as numingredients
      from @RecipeIngredient ri
     ) ri2
     on ri1.ingredientId = ri2.ingredientId and
        ri1.quantity = ri2.quantity and
        ri1.recipeId < ri2.recipeId
group by ri1.recipeId, ri2.recipeId
having max(ri1.numingredients) = max(ri2.numingredients) and
       max(ri1.numingredients) = count(*)

having子句保证每个食谱的成分数量相同,并且匹配成分的数量是总数。这一次,我在以下数据上进行了测试:

insert into @recipeingredient select 1, 1, 1
insert into @recipeingredient select 1, 2, 10
insert into @recipeingredient select 2, 1, 1
insert into @recipeingredient select 2, 2, 10
insert into @recipeingredient select 2, 3, 10
insert into @recipeingredient select 3, 1, 1
insert into @recipeingredient select 4, 1, 1
insert into @recipeingredient select 4, 3, 10
insert into @recipeingredient select 5, 1, 1
insert into @recipeingredient select 5, 2, 10

如果你有一个新的配方,你可以修改这个查询,只在一个表(比如 ri1)中使用on子句上的附加条件来查找配方。

如果将成分放在临时表中,则可以用新表替换其中一个表,例如 ri1。

于 2012-09-25T15:03:22.290 回答
0

您可以尝试这样的方法来查找是否有重复项:

-- Setup test data
declare @recipeingredient table (
      id int not null primary key identity
    , recipeId int not null
    , ingredientId int not null
    , quantity int not null
)
insert into @recipeingredient select 1, 1, 1
insert into @recipeingredient select 1, 2, 10
insert into @recipeingredient select 2, 1, 1
insert into @recipeingredient select 2, 2, 10

-- Actual Query
if exists (
    select *
    from @recipeingredient old
        full outer join @recipeingredient new
            on old.recipeId != new.recipeId         -- Different recipes
            and old.ingredientId = new.ingredientId -- but same ingredients
            and old.quantity = new.quantity         -- and same quantities
    where old.id is null    -- Match not found
        or new.id is null   -- Match not found
)
begin
    select cast(0 as bit) as IsDuplicateRecipe
end
else begin
    select cast(1 as bit) as IsDuplicateRecipe
end

由于这实际上只是在搜索重复项,因此您可能希望替换一个临时表或为“新”表传递一个表变量。这样您就不必在进行搜索之前插入新记录。您还可以插入基表,将整个事物包装在事务中并根据结果回滚。

于 2012-09-25T15:36:41.283 回答