2

私は3つのテーブルを持っています:

  • レシピ:
    • ID、名前
  • 成分:
    • ID、名前
  • レシピ成分:
    • ID、レシピ ID、材料 ID、数量

顧客が新しいレシピを作成するたびに、recipeingredientテーブルをチェックして、このレシピが存在するかどうかを確認する必要があります。ingredientIdとがまったく同じである場合quantityは、レシピが既に存在することを顧客に伝えます。複数の行をチェックする必要があるため、このクエリを作成するには助けが必要です。

4

3 に答える 3

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

新しいレシピがある場合は、このクエリを変更して、on句に追加の条件を使用して、テーブルの 1 つ (ri1 など) でレシピを検索するだけにすることができます。

材料を一時テーブルに配置する場合、これらのテーブルの 1 つ (ri1 など) を新しいテーブルに置き換えることができます。

于 2012-09-25T15:03:22.290 に答える
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 に答える
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 に答える