【问题标题】:SQL Server 2008, how to check if multi records exist in the DB?SQL Server 2008,如何检查数据库中是否存在多条记录?
【发布时间】:2012-09-26 03:24:37
【问题描述】:

我有 3 张桌子:

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

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

【问题讨论】:

  • 你如何代表新配方?是否在同一张表中、临时表中、内存中?
  • @GordonLinoff 我假设这是一个表单帖子......但很好的问题。

标签: sql sql-server sql-server-2008 duplicates


【解决方案1】:

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

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

【讨论】:

    【解决方案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 子句上的附加条件,仅在其中一个表(例如 ri1)中查找配方。

    如果您将配料放在临时表中,您可以用新表替换其中一个表,例如 ri1。

    【讨论】:

    • @TimLehner 。 . .您能否详细说明数据的错误或问题?
    • 当然,用我的答案数据试试(这与你的方向基本相同)。然后改变一个数量。或添加/删除一行。您的 group by 实际上可能掩盖了食谱之间的任何差异。
    • 我运行它,它说食谱 1 和 2 具有相同的成分。它是成对地计算结果,所以这显示为 1 和 2 以及 2 和 1 的两倍。我正在修复答案以防止这种情况发生。
    • 对不起,我没有说得更清楚。无论我制作什么成分,这似乎都会返回相同的东西。不管我设置什么成分,如果我有两个食谱,它总是会返回一行 1, 2
    • @TimLehner 。 . .哦,一个难题。我通常不会对完全外部连接感到困惑,但我做到了。修改后的版本确实有效。
    【解决方案3】:

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

    -- 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
    

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

    【讨论】:

      猜你喜欢
      • 2010-10-15
      • 1970-01-01
      • 2020-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-07
      相关资源
      最近更新 更多