2

我的 Oracle 数据库中有两个表productproduct_image. product它们具有从到的一对多关系product_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;
}

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

这是我以前的问题。这可以通过以下 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

该问题的答案对应于以下正确的 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子句中进行子查询,FROM在 HQL 中不允许子句中的子查询。

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;

我的谷歌搜索表明这对于单个 HQL 语句是不可行的。这对 HQL 有可能吗?请确认我。

4

4 回答 4

2

你是对的,你不能在 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

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

于 2013-04-07T20:11:41.417 回答
1

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

于 2013-04-07T17:52:24.013 回答
0

我目前在 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 系统中看到的方式,但它可以工作。

于 2013-11-19T14:24:34.487 回答
0

如果对查询语句稍作修改,就可以做到这一点。因此,以下标准查询确实需要。

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
于 2014-06-07T08:20:21.577 回答