Hibernate Criteria - 返回列不同的记录

时间:2012-08-13 23:22:03

标签: java hibernate criteria-api

示例数据库表:

  1. ID = 1,msgFrom ='Hello',foobar ='meh'
  2. ID = 2,msgFrom ='Goodbye',foobar ='comments'
  3. ID = 3,msgFrom ='Hello',foobar ='response'
  4. 示例所需的输出(由hibernate查询生成):

    1. ID = 1,msgFrom ='Hello',foobar ='meh'
    2. ID = 2,msgFrom ='Goodbye',foobar ='comments'
    3. 在上面的示例中,第三条记录将从结果中排除,因为msgFrom列是相同的。假设Java / Hibernate类叫做Message。我希望结果作为Message对象列表(或者可以转换为Message的对象)返回。我想尽可能使用Criteria API。我在SO上看到了这个例子,看起来很相似,但我还没有正确实现它。

       select e from Message e 
          where e.msgFrom IN (select distinct m.msgFrom 
                                from Message m
                                WHERE m.msgTo = ? 
                                AND m.msgCheck = 0");
      

      我这样做的原因是要对数据库上的不同记录进行过滤,所以我对我必须在应用程序服务器上过滤任何内容的答案不感兴趣。

      编辑:文章基本上显示了我想要做的事情。 http://oscarvalles.wordpress.com/2008/01/28/sql-distinct-on-one-column-only/

3 个答案:

答案 0 :(得分:6)

请尝试这个并告诉我

DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
ProjectionList properties = Projections.projectionList();
properties.add(Projections.groupProperty("messageFrom"));
properties.add(Projections.min("id"),"id");
msgFromCriteria.setProjection(properties);

Criteria criteria = s.createCriteria(Message.class);
criteria.add(Subqueries.propertiesIn(new String[]{"messageFrom","id"}, 
    msgFromCriteria));
List<Message> list = criteria.list();

for(Message message:list){
    System.out.println(message.getId()
        +"-------"
        +message.getMessageFrom()
        +"-----"
        +message.getFoobar());
}

答案 1 :(得分:2)

这个查询的难度本身并不是Hibernate,而是一般的关系模型。在示例中,您说您期望第1行和第2行,但为什么不能轻易地期望第2行和第3行?由于它们在msgFrom字段中具有相同的值,因此返回第1行或第3行将是一个任意的决定。数据库不会像这样做出任意决定。这就是为什么distinct必须应用于整个选择列列表而不是子集的原因。有特定于数据库的方法来获取第一个匹配的行。例如,看看

SELECT DISTINCT on one column

有时会有一个日期列,您可以使用它来决定返回哪些匹配的行,但是查询再次变得有些复杂:

How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?

Fetch the row which has the Max value for a column

如果您不关心任何其他列,您可以使用简单的distinct,结合Hibernate的构造函数语法(未经测试):

select new Message(msgFrom) from (select distinct msgFrom from Message)

但你必须接受丢弃所有其他列。

最后,我经常最终只是在代码中这样做作为帖子查询过滤器。另一种选择是创建另一个表,比如说CurrentMessage,它包含作为键的一部分的msgFrom。将更多工作保持此表是最新的(每次向Message表添加行时都需要更新行)但查询将更容易。

答案 2 :(得分:0)

DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
msgFromCriteria.setProjection(Projections.distinct(Projections.property("msgFrom")));
....
Criteria criteria = getSession().createCriteria(Message.class);
criteria.add(Subqueries.propertyIn("msgFrom", msgFromCriteria));
criteria.list();