【问题标题】:Postgres SQL / HQL query structure comparing 2 listsPostgres SQL / HQL 查询结构比较 2 个列表
【发布时间】:2015-10-25 22:20:20
【问题描述】:

我有一个 FridgeContents 表、一个食谱表和一个 RecipeIngredients 表。

CREATE TABLE Recipes
(
  id bigserial NOT NULL,
  name text
);
CREATE TABLE Ingredients
(
  id bigserial NOT NULL,
  name text,
  description text
);
CREATE TABLE RecipeIngredients
(
  id bigserial NOT NULL,
  recipe_id bigint REFERENCES Recipes(id),
  ingredient_id bigint REFERENCES Ingredients(id),
  quantity numeric
);
CREATE TABLE FridgeContents
(
  id bigserial NOT NULL,
  ingredient_id bigint REFERENCES Ingredients(id),
  quantity numeric
);

我正在使用 Hibernate、Spring Data JPA 和 postgresql 数据库开发 SpringBoot 应用程序。

我正在尝试构建一个查询,该查询将返回一个列表,其中列出了我可以根据我当前的成分制作的所有食谱。

一种方法是按顺序提取食谱的所有成分,从我的 FridgeContents 中检查它们,如果 RecipeIngredients 列表的其余部分为空,则返回 true,但这听起来效率低下,尤其是在我有 1000 份食谱的情况下。

这样的东西会起作用吗?我可以使用一些更好的技巧吗?

Select * from Recipes where id in (
  Select distinct recipe_id from RecipeIngredients EXCEPT (
    Select distinct recipe_id from RecipeIngredients
    where ingredient_id NOT in (
      Select ingredient_id from FridgeContents
    )
  )
);

【问题讨论】:

  • 添加了关系划分标签。只允许五个标签,所以我不得不删除 HQL。
  • 您想用冰箱里的东西准备多个食谱吗? (在 SQL 中不可能,需要回溯或某种动态编程;此外:不止一种可能的解决方案)
  • 就本练习而言,我只对准备一个食谱感兴趣,所以只想要一份我可以制作的所有可能食谱的列表。

标签: sql hibernate postgresql spring-data-jpa relational-division


【解决方案1】:

我会使用连接和聚合来解决这个问题:

select ri.recipe_id
from recipeingredients ri left join
     fridgecontents fc
     on ri.ingredient_id = fc.ingredient_id
group by recipe_id
having count(*) = count(fc.ingredient_id);

having 子句本质上是说:食谱的所有成分都可以在冰箱中找到。注意:如果冰箱或食谱可能有重复的成分,那么您应该使用:

having count(distinct ri.ingredient_id) = count(distinct fc.ingredient_id)

【讨论】:

  • 我将它用作 JPA 命名查询的一部分,它很有效。谢谢
【解决方案2】:

用于关系除法的双 NOT EXISTS() 构造。注意:结果还将包括完全没有成分的食谱...

SELECT * 
FROM recipes r
        -- ## You cannot make a recipe
WHERE NOT EXISTS (
        SELECT *
        FROM recipe_ingredients ri
        WHERE ri.recipe_id = r.id
        -- ## ... for which any of the ingredients
        -- ## ... is *NOT* available
        AND NOT EXISTS ( 
                SELECT * FROM fridgecontents fc
                WHERE fc.ingredient_id = ri.ingredient_id
                AND fc.quantity >= ri.quantity
                )
        );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    • 2011-08-17
    • 1970-01-01
    • 1970-01-01
    • 2015-08-07
    • 2016-07-24
    • 1970-01-01
    相关资源
    最近更新 更多