求教!用hibernate,怎么用count(),sum(),怎么能根据条件查询,执行语句? Java / 框架、开源

2007-08-16  不会游泳...

11.12.   HQL示例  
  Hibernate查询可以非常强大复杂。实际上,强有力的查询语言是Hibernate的主要卖点之一。下面给出的示例与我在近期实际项目中使用的一些查询很类似。请注意你编写的查询大部分等都不会这么复杂!    
   
  下面的查询对特定的客户,根据给定的最小总计值(minAmount),查询出所有未付订单,返回其订单号、货品总数、订单总金额,结果按照总金额排序。在决定价格的时候,参考当前目录。产生的SQL查询,在ORDER,ORDER_LINE,PRODUCT,CATALOG和PRICE表之间有四个内部连接和一个没有产生关联的字查询。    
   
  select   order.id,   sum(price.amount),   count(item)  
  from   Order   as   order  
          join   order.lineItems   as   item  
          join   item.product   as   product,  
          Catalog   as   catalog  
          join   catalog.prices   as   price  
  where   order.paid   =   false  
          and   order.customer   =   :customer  
          and   price.product   =   product  
          and   catalog.effectiveDate   <   sysdate  
          and   catalog.effectiveDate   >=   all   (  
                  select   cat.effectiveDate    
                  from   Catalog   as   cat  
                  where   cat.effectiveDate   <   sysdate  
          )  
  group   by   order  
  having   sum(price.amount)   >   :minAmount  
  order   by   sum(price.amount)   desc  
  好家伙,真长!实际上,在现实生活中我并不是非常热衷于子查询,所以我的查询往往是这样的:    
   
  select   order.id,   sum(price.amount),   count(item)  
  from   Order   as   order  
          join   order.lineItems   as   item  
          join   item.product   as   product,  
          Catalog   as   catalog  
          join   catalog.prices   as   price  
  where   order.paid   =   false  
          and   order.customer   =   :customer  
          and   price.product   =   product  
          and   catalog   =   :currentCatalog  
  group   by   order  
  having   sum(price.amount)   >   :minAmount  
  order   by   sum(price.amount)   desc  
  下面的查询统计付款记录处于每种状态中的数量,要排除所有处于AWAITING_APPROVAL状态的,或者最近一次状态更改是由当前用户做出的。它翻译成SQL查询后,在PAYMENT,PAYMENT_STATUS和PAYMENT_STATUS_CHANGE表之间包含两个内部连接和一个用于关联的子查询。    
   
  select   count(payment),   status.name    
  from   Payment   as   payment    
          join   payment.currentStatus   as   status  
          join   payment.statusChanges   as   statusChange  
  where   payment.status.name   <>   PaymentStatus.AWAITING_APPROVAL  
          or   (  
                  statusChange.timeStamp   =   (    
                          select   max(change.timeStamp)    
                          from   PaymentStatusChange   change    
                          where   change.payment   =   payment  
                  )  
                  and   statusChange.user   <>   :currentUser  
          )  
  group   by   status.name,   status.sortOrder  
  order   by   status.sortOrder  
  假若我已经把statusChange集合映射为一个列表而不是一个集合的话,查询写起来会简单很多。    
   
  select   count(payment),   status.name    
  from   Payment   as   payment  
          join   payment.currentStatus   as   status  
  where   payment.status.name   <>   PaymentStatus.AWAITING_APPROVAL  
          or   payment.statusChanges[   maxIndex(payment.statusChanges)   ].user   <>   :currentUser  
  group   by   status.name,   status.sortOrder  
  order   by   status.sortOrder  
  下面的查询使用了MS   SQL   Server的isNull()函数,返回当前用户所属的组织所有账户和未付支出。翻译为SQL查询后,在ACCOUNT,   PAYMENT,   PAYMENT_STATUS,ACCOUNT_TYPE,   ORGANIZATION   和   ORG_USER表之间有三个内部连接,一个外部连接和一个子查询。    
   
  select   account,   payment  
  from   Account   as   account  
          left   outer   join   account.payments   as   payment  
  where   :currentUser   in   elements(account.holder.users)  
          and   PaymentStatus.UNPAID   =   isNull(payment.currentStatus.name,   PaymentStatus.UNPAID)  
  order   by   account.type.sortOrder,   account.accountNumber,   payment.dueDate  
  对某些数据库而言,我们可能不能依赖(关联的)子查询。    
   
  select   account,   payment  
  from   Account   as   account  
          join   account.holder.users   as   user  
          left   outer   join   account.payments   as   payment  
  where   :currentUser   =   user  
          and   PaymentStatus.UNPAID   =   isNull(payment.currentStatus.name,   PaymentStatus.UNPAID)  
  order   by   account.type.sortOrder,   account.accountNumber,   payment.dueDate  
  Top

9 楼IceCraft(心淡情浓)回复于 2004-10-26 13:03:30 得分 0

第   11   章   Hibernate查询语言(Query   Language),   即HQL    
  上一页           下一页    
   
  --------------------------------------------------------------------------------  
   
  第   11   章   Hibernate查询语言(Query   Language),   即HQL  
  Hibernate装备了一种极为有力的查询语言,(有意地)看上去很像SQL。但是别被语法蒙蔽,HQL是完全面向对象的,具备继承、多态和关联等特性。    
   
  11.1.   大小写敏感性(Case   Sensitivity)  
  除了Java类和属性名称外,查询都是大小写不敏感的。   所以,   SeLeCT   和   sELEct   以及   SELECT   相同的,但是   net.sf.hibernate.eg.FOO   和   net.sf.hibernate.eg.Foo   是不同的,   foo.barSet   和   foo.BARSET也是不同的。    
   
  本手册使用小写的HQL关键词。有些用户认为在查询中使用大写的关键字更加易读,但是我们认为嵌入在Java代码中这样很难看。    
   
  11.2.   from   子句  
  可能最简单的Hibernate查询是这样的形式:    
   
  from   eg.Cat  
  它简单的返回所有eg.Cat类的实例。    
   
  大部分情况下,你需要赋予它一个别名(alias),因为你在查询的其他地方也会引用这个Cat。    
   
  from   eg.Cat   as   cat  
  上面的语句为Cat赋予了一个别名cat   。所以后面的查询可以用这个简单的别名了。as关键字是可以省略的,我们也可以写成这样:    
   
  from   eg.Cat   cat  
  可以出现多个类,结果是它们的笛卡尔积,或者称为“交叉”连接。    
   
  from   Formula,   Parameter  
  from   Formula   as   form,   Parameter   as   param  
  让查询中的别名服从首字母小写的规则,我们认为这是一个好习惯。这和Java对局部变量的命名规范是一致的。(比如,domesticCat).    
   
  11.3.   联合(Associations)和连接(joins)  
  你可以使用join定义两个实体的连接,同时指明别名。    
   
  from   eg.Cat   as   cat    
          inner   join   cat.mate   as   mate  
          left   outer   join   cat.kittens   as   kitten  
   
  from   eg.Cat   as   cat   left   join   cat.mate.kittens   as   kittens  
   
  from   Formula   form   full   join   form.parameter   param  
  支持的连接类型是从ANSI   SQL借用的:    
   
  内连接,inner   join    
   
  左外连接,left   outer   join    
   
  右外连接,right   outer   join    
   
  全连接,full   join   (不常使用)    
   
  inner   join,   left   outer   join   和   right   outer   join   都可以简写。    
   
  from   eg.Cat   as   cat    
          join   cat.mate   as   mate  
          left   join   cat.kittens   as   kitten  
  并且,加上   "fetch"后缀的抓取连接可以让联合的对象随着它们的父对象的初始化而初始化,只需要一个select语句。这在初始化一个集合的时候特别有用。它有效地覆盖了映射文件中对关联和集合的外连接定义。    
   
  from   eg.Cat   as   cat    
          inner   join   fetch   cat.mate  
          left   join   fetch   cat.kittens  
  抓取连接一般不需要赋予别名,因为被联合的对象应该不会在where子句(或者任何其它子句)中出现。并且,被联合的对象也不会在查询结果中直接出现。它们是通过父对象进行访问的。    
   
  请注意,目前的实现中,在一次查询中只会抓取一个集合(其他的一切都做不到。)(?原文为:only   one   collection   role   may   be   fetched   in   a   query)。也请注意,在使用scroll()或者   iterate()方式调用的查询中,是禁止使用fetch构造的。最后,请注意full   join   fetch和right   join   fetch是没有意义的。    
   
  11.4.   select子句  
  select子句选择在结果集中返回哪些对象和属性。思考一下下面的例子:    
   
  select   mate    
  from   eg.Cat   as   cat    
          inner   join   cat.mate   as   mate  
  这个查询会选择出作为其它猫(Cat)朋友(mate)的那些猫。当然,你可以更加直接的写成下面的形式:    
   
  select   cat.mate   from   eg.Cat   cat  
  你甚至可以选择集合元素,使用特殊的elements功能。下面的查询返回所有猫的小猫。    
   
  select   elements(cat.kittens)   from   eg.Cat   cat  
  查询可以返回任何值类型的属性,包括组件类型的属性:    
   
  select   cat.name   from   eg.DomesticCat   cat  
  where   cat.name   like   ‘fri%‘  
   
  select   cust.name.firstName   from   Customer   as   cust  
  查询可以用元素类型是Object[]的一个数组返回多个对象和/或多个属性。    
   
  select   mother,   offspr,   mate.name    
  from   eg.DomesticCat   as   mother  
          inner   join   mother.mate   as   mate  
          left   outer   join   mother.kittens   as   offspr  
  或者实际上是类型安全的Java对象    
   
  select   new   Family(mother,   mate,   offspr)  
  from   eg.DomesticCat   as   mother  
          join   mother.mate   as   mate  
          left   join   mother.kittens   as   offspr  
  上面的代码假定Family有一个合适的构造函数。    
   
  11.5.   统计函数(Aggregate   functions)  
  HQL查询可以返回属性的统计函数的结果。    
   
  select   avg(cat.weight),   sum(cat.weight),   max(cat.weight),   count(cat)  
  from   eg.Cat   cat  
  在select子句中,统计函数的变量也可以是集合。    
   
  select   cat,   count(   elements(cat.kittens)   )    
  from   eg.Cat   cat   group   by   cat  
  下面是支持的统计函数列表:    
   
  avg(...),   sum(...),   min(...),   max(...)    
   
  count(*)    
   
  count(...),   count(distinct   ...),   count(all...)    
   
  distinct   和   all关键字的用法和语义与SQL相同。    
   
  select   distinct   cat.name   from   eg.Cat   cat  
   
  select   count(distinct   cat.name),   count(cat)   from   eg.Cat   cat  
  11.6.   多态(polymorphism)查询  
  类似下面的查询:    
   
  from   eg.Cat   as   cat  
  返回的实例不仅仅是Cat,也有可能是子类的实例,比如DomesticCat。Hibernate查询可以在from子句中使用任何Java类或者接口的名字。查询可能返回所有继承自这个类或者实现这个接口的持久化类的实例。下列查询会返回所有的持久化对象:    
   
  from   java.lang.Object   o  
  可能有多个持久化类都实现了Named接口:    
   
  from   eg.Named   n,   eg.Named   m   where   n.name   =   m.name  
  请注意,上面两个查询都使用了超过一个SQL的SELECT。这意味着order   by子句将不会正确排序。(这也意味着你不能对这些查询使用Query.scroll()。)    
   
  11.7.   where子句  
  where子句让你缩小你要返回的实例的列表范围。    
   
  from   eg.Cat   as   cat   where   cat.name=‘Fritz‘  
  返回所有名字为‘Fritz‘的Cat的实例。    
   
  select   foo    
  from   eg.Foo   foo,   eg.Bar   bar  
  where   foo.startDate   =   bar.date  
  会返回所有的满足下列条件的Foo实例,它们存在一个对应的bar实例,其date属性与Foo的startDate属性相等。复合路径表达式令where子句变得极为有力。思考下面的例子:    
   
  from   eg.Cat   cat   where   cat.mate.name   is   not   null  
  这个查询会被翻译为带有一个表间(inner)join的SQL查询。如果你写下类似这样的语句:    
   
  from   eg.Foo   foo      
  where   foo.bar.baz.customer.address.city   is   not   null  
  你最终会得到的查询,其对应的SQL需要4个表间连接。    
   
  =操作符不仅仅用于判断属性是否相等,也可以用于实例:    
   
  from   eg.Cat   cat,   eg.Cat   rival   where   cat.mate   =   rival.mate  
   
  select   cat,   mate    
  from   eg.Cat   cat,   eg.Cat   mate  
  where   cat.mate   =   mate  
  特别的,小写的id可以用来表示一个对象的惟一标识。(你可以使用它的属性名。)    
   
  from   eg.Cat   as   cat   where   cat.id   =   123  
   
  from   eg.Cat   as   cat   where   cat.mate.id   =   69  
  第二个查询是很高效的。不需要进行表间连接!    
   
  组合的标示符也可以使用。假设Person有一个组合标示符,是由country和medicareNumber组合而成的。    
   
  from   bank.Person   person  
  where   person.id.country   =   ‘AU‘    
          and   person.id.medicareNumber   =   123456  
   
  from   bank.Account   account  
  where   account.owner.id.country   =   ‘AU‘    
          and   account.owner.id.medicareNumber   =   123456  
  又一次,第二个查询不需要表间连接。    
   
  类似的,在存在多态持久化的情况下,特殊属性class用于获取某个实例的辨识值。在where子句中嵌入的Java类名将会转换为它的辨识值。    
   
  from   eg.Cat   cat   where   cat.class   =   eg.DomesticCat  
  你也可以指定组件(或者是组件的组件,依次类推)或者组合类型中的属性。但是在一个存在路径的表达式中,最后不能以一个组件类型的属性结尾。(这里不是指组件的属性)。比如,假若store.owner这个实体的的address是一个组件    
   
  store.owner.address.city         //okay  
  store.owner.address                   //error!  
  “任意(any)”类型也有特殊的id属性和class属性,这可以让我们用下面的形式来表达连接(这里AuditLog.item是一个对应到<ant>的属性)。    
   
  from   eg.AuditLog   log,   eg.Payment   payment    
  where   log.item.class   =   ‘eg.Payment‘   and   log.item.id   =   payment.id  
  注意上面查询中,log.item.class和payment.class会指向两个值,代表完全不同的数据库字段。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。如发现有害或侵权内容,请点击这里 或 拨打24小时举报电话:4000070609 与我们联系。

    猜你喜欢

    0条评论

    发表

    请遵守用户 评论公约

    类似文章
    喜欢该文的人也喜欢 更多