【问题标题】:The greatest row per group - further combining the result set with left join with other related table in Hibernate - HQL. Is it possible?每组最大的行 - 进一步将结果集与左连接与 Hibernate 中的其他相关表相结合 - HQL。可能吗?
【发布时间】:2013-04-07 12:25:53
【问题描述】:

我的 Oracle 数据库中有两个表 productproduct_image。它们具有从productproduct_image 的一对多关系。因此,这种关系可以在 Hibernate 中映射如下。

产品实体:

@Entity
@Table(name = "PRODUCT", catalog = "", schema = "WAGAFASHIONDB")
public class Product  implements java.io.Serializable
{
    @OneToMany(mappedBy = "prodId", fetch = FetchType.LAZY)
    private Set<ProductImage> productImageSet; 
}

@Entity
@Table(name = "PRODUCT_IMAGE", catalog = "", schema = "WAGAFASHIONDB")
public class ProductImage  implements java.io.Serializable
{
    @ManyToOne(fetch = FetchType.LAZY)
    private Product prodId;
}

我需要查询可以从product_image 表中的每组产品中获取具有最大prod_image_idprduct_image 表的主键)的行列表。

这是我的previous question。这可以通过以下 SQL 完成。

SELECT 
     pi.prod_image_id,
     pi.prod_id, pi.prod_image 
FROM 
     product_image pi 
INNER JOIN (
     SELECT 
          MAX(pi.prod_image_id) AS prod_image_id 
     FROM 
          product_image pi 
     GROUP BY 
          pi.prod_id
     ) prod_image 
ON pi.prod_image_id=prod_image.prod_image_id

该问题的answer 对应于以下正确的 HQL。

SELECT 
    pi.prodImageId, 
    pi.prodId 
FROM 
    ProductImage pi 
WHERE 
    pi.prodImageId in (
    SELECT
         MAX(pis.prodImageId)
    FROM 
         Product p
    INNER JOIN 
         p.productImageSet pis
    GROUP BY 
         p.prodId
)

这完全符合预期的结果。

PROD_IMAGE_ID     PROD_ID      PROD_IMAGE
662               284          3562298873030291049_Winter.jpg
644               283          7551758088174802741_9392401244_SS_2505.jpg
595               124          298082252715152799_SS_5012.jpg
566               62           7826143854352037374_SS_5004-A.jpg

但我真正需要的是,上面的SQL/HQL检索到的结果集需要与product表和LEFT OUTER JOIN结合起来,这样它就可以从product表中检索每个产品,而不管它们的product_image 表中的图像类似于以下内容。

PROD_IMAGE_ID     PROD_ID      PROD_IMAGE
662               284          3562298873030291049_Winter.jpg
644               283          7551758088174802741_9392401244_SS_2505.jpg
595               124          298082252715152799_SS_5012.jpg
 -                101                -
 -                81                 - 
566               62           7826143854352037374_SS_5004-A.jpg

这可以通过以下本机 SQL 来完成,但使用 HQL 似乎不可能,因为 HQL 只允许在 SELECTWHERE 子句中进行子查询,而在 HQL 中不允许 FROM 子句中的子查询。

SELECT 
     t.prod_image_id,
     p.prod_id,
     t.prod_image 
FROM
     product p 
LEFT OUTER JOIN(
     SELECT 
           pi.prod_image_id,
           pi.prod_id,
           pi.prod_image 
     FROM
           product_image pi 
     INNER JOIN (
           SELECT 
                MAX(pi.prod_image_id) AS prod_image_id 
           FROM 
                product_image pi
           GROUP BY 
                pi.prod_id
     ) prod_image 
     ON pi.prod_image_id=prod_image.prod_image_id
)t ON p.prod_id=t.prod_id ORDER BY p.prod_id DESC;

我的 Google 搜索显示,这对于单个 HQL 语句是不可行的。这对 HQL 有可能吗?请确认我。

【问题讨论】:

  • 使用窗口(又称分析)函数将比使用子选择更有效。
  • @a_horse_with_no_name :根据this 的回答,Hibernate 中不允许使用窗口函数。 HQL 不支持窗口函数。
  • 啊,ORM 工具的“乐趣”。这简直太愚蠢了,我知道我为什么不喜欢 ORM

标签: oracle hibernate oracle10g hql greatest-n-per-group


【解决方案1】:

你是对的,你不能在 from 子句中使用子查询。

http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/#queryhql-subqueries

但您可以使用单独的查询,例如:

select p 
from Product p 
where p.productImageSet is empty

查找没有产品图片的产品。

【讨论】:

  • 我现在正在获取包含相应图像的 Set&lt;Product&gt; - 每个产品的 productImageSet 并在视图上处理它们 - 使用 JSTL 的 JSP - 使用 @987654326 迭代 Set @循环,找到prodImageId的最大值等等。这可能是一项乏味的工作,但似乎比其他方式更合理。谢谢。
【解决方案2】:

我将创建一个 Oracle 视图来实现您的查询,通过 HQL 中的简单选择为您提供所需的内容。

【讨论】:

  • 很遗憾,一个视图不能直接通过HQL查询。 HQL 基本上用于查询表示数据库中表之间关系的实体类(据我所知)。谢谢。
  • 哇。那么 HQL 是如何知道视图和表的区别的呢?您不能将视图建模为另一个表吗?
  • 一个视图可以是accessed,通过 Hibernate 通过 HQL 并为该特定视图提供一个单独的实体类。我不知道,稍后会试一试。
【解决方案3】:

我目前在 MySQL 中具有相同的表关系。我目前正在尝试学习JPA。因此,我使用的是 Hibernate 提供的 JPA 2.0 - 最终版本 4.2.7。以下JPQL,

select 
      p.prodId, 
      pi.productImageId, 
      p.prodName, 
      pi.prodImage 
from 
      Product p 
left join 
      p.productImageSet pi 
where 
      pi.productImageId in (
          select 
               max(productImageId) as productImageId 
          from  
               ProductImage 
          group by 
               prodId
   ) 
or pi.productImageId is null
order by p.prodId  

以及对应的条件查询,

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createTupleQuery();
Metamodel metamodel=entityManager.getMetamodel();
EntityType<Product>entityType=metamodel.entity(Product.class);
Root<Product>root=criteriaQuery.from(entityType);
SetJoin<Product, ProductImage> join = root.join(Product_.productImageSet, JoinType.LEFT);

List<Selection<?>>selections=new ArrayList<Selection<?>>();
selections.add(root.get(Product_.prodId));
selections.add(root.get(Product_.prodName));
selections.add(join.get(ProductImage_.prodImage));
selections.add(join.get(ProductImage_.productImageId));
criteriaQuery.multiselect(selections);

Subquery<Long>subquery=criteriaQuery.subquery(Long.class);
Root<ProductImage> subRoot = subquery.from(ProductImage.class);
subquery.select(criteriaBuilder.max(subRoot.get(ProductImage_.productImageId)));
subquery.groupBy(subRoot.get(ProductImage_.prodId).get(Product_.prodId));

Predicate []predicates=new Predicate[2];
predicates[0]=criteriaBuilder.in(join.get(ProductImage_.productImageId)).value(subquery);
predicates[1]=join.get(ProductImage_.productImageId).isNull();

criteriaQuery.where(criteriaBuilder.or(predicates));
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Product_.prodId)));

TypedQuery<Tuple> typedQuery = entityManager.createQuery(criteriaQuery);
List<Tuple> tuples = typedQuery.getResultList();

JPQL 和条件查询都产生以下 SQL 查询。

select
    product0_.prod_id as col_0_0_,
    productima1_.product_image_id as col_1_0_,
    product0_.prod_name as col_2_0_,
    productima1_.prod_image as col_3_0_ 
from
    social_networking.product product0_ 
left outer join
    social_networking.product_image productima1_ 
        on product0_.prod_id=productima1_.prod_id 
where
    productima1_.product_image_id in (
        select
            max(productima2_.product_image_id) 
        from
            social_networking.product_image productima2_ 
        group by
            productima2_.prod_id
    ) 
    or productima1_.product_image_id is null 
order by
    product0_.prod_id desc

导致获取问题中提到的所需结果集 - 不是我们在通常的 RDBMS 系统中看到的方式,但它可以工作。

【讨论】:

    【解决方案4】:

    如果查询语句稍作修改,就可以做到这一点。因此,以下条件查询可以满足您的需求。

    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<ProductUtils>criteriaQuery=criteriaBuilder.createQuery(ProductUtils.class);
    Metamodel metamodel = entityManager.getMetamodel();
    Root<Product> root = criteriaQuery.from(metamodel.entity(Product.class));
    
    ListJoin<Product, ProductImage> join = root.join(Product_.productImageList, JoinType.LEFT);
    
    List<Selection<?>>selections=new ArrayList<Selection<?>>();
    selections.add(root.get(Product_.prodId));
    selections.add(root.get(Product_.prodName));
    selections.add(join.get(ProductImage_.prodImage));
    selections.add(join.get(ProductImage_.productImageId));
    criteriaQuery.select(criteriaBuilder.construct(ProductUtils.class, selections.toArray(new Selection[0])));
    
    Subquery<Long> subquery = criteriaQuery.subquery(Long.class);
    Root<ProductImage> prodImageRoot = subquery.from(metamodel.entity(ProductImage.class));
    subquery.select(prodImageRoot.get(ProductImage_.productImageId));
    subquery.where(criteriaBuilder.equal(root, prodImageRoot.get(ProductImage_.prodId)), criteriaBuilder.lessThan(join.get(ProductImage_.productImageId), prodImageRoot.get(ProductImage_.productImageId)));
    
    criteriaQuery.where(criteriaBuilder.exists(subquery).not());
    criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Product_.prodId)));
    List<ProductUtils> list = entityManager.createQuery(criteriaQuery).getResultList();
    

    此条件查询生成以下所需的 SQL 查询,该查询执行与问题中指定的相同功能。

    select
        product0_.prod_id as col_0_0_,
        product0_.prod_name as col_1_0_,
        productima1_.prod_image as col_2_0_ ,
        productima1_.product_image_id as col_3_0_ 
    from
        social_networking.product product0_ 
    left outer join
        social_networking.product_image productima1_ 
            on product0_.prod_id=productima1_.prod_id 
    where
        not (exists (select
            productima2_.product_image_id 
        from
            social_networking.product_image productima2_ 
        where
            product0_.prod_id=productima2_.prod_id 
            and productima1_.product_image_id<productima2_.product_image_id)) 
    order by
        product0_.prod_id desc
    

    【讨论】:

      猜你喜欢
      • 2021-05-03
      • 2012-02-19
      • 1970-01-01
      • 1970-01-01
      • 2015-03-18
      • 1970-01-01
      • 2016-12-19
      • 2017-10-06
      • 1970-01-01
      相关资源
      最近更新 更多