5

示例数据库表:

  1. ID = 1,msgFrom = '你好',foobar = 'meh'
  2. ID = 2,msgFrom = '再见',foobar = '评论'
  3. ID = 3,msgFrom = '你好',foobar = '响应'

示例所需的输出(由休眠查询生成):

  1. ID = 1,msgFrom = '你好',foobar = 'meh'
  2. ID = 2,msgFrom = '再见',foobar = '评论'

在上面的示例中,第三条记录将从结果中排除,因为 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/

4

3 回答 3

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());
}
于 2012-08-23T18:21:26.743 回答
2

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

在一列上选择 DISTINCT

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

如何在 SQL 中通过另一列选择具有 MAX(列值)、DISTINCT 的行?

获取列的最大值所在的行

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

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

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

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

于 2012-08-16T19:39:47.000 回答
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();
于 2012-08-13T23:56:23.893 回答