📄 queryhql.html
字号:
</p><pre class="programlisting">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 pricewhere 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 orderhaving sum(price.amount) > :minAmountorder by sum(price.amount) desc</pre><p> 好家伙,真长!实际上,在现实生活中我并不是非常热衷于子查询,所以我的查询往往是这样的: </p><pre class="programlisting">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 pricewhere order.paid = false and order.customer = :customer and price.product = product and catalog = :currentCataloggroup by orderhaving sum(price.amount) > :minAmountorder by sum(price.amount) desc</pre><p> 下面的查询统计付款记录处于每种状态中的数量,要排除所有处于<tt class="literal">AWAITING_APPROVAL</tt>状态的,或者最近一次状态更改是由当前用户做出的。它翻译成SQL查询后,在<tt class="literal">PAYMENT</tt>,<tt class="literal">PAYMENT_STATUS</tt>和<tt class="literal">PAYMENT_STATUS_CHANGE</tt>表之间包含两个内部连接和一个用于关联的子查询。 </p><pre class="programlisting">select count(payment), status.name from Payment as payment join payment.currentStatus as status join payment.statusChanges as statusChangewhere 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.sortOrderorder by status.sortOrder</pre><p> 假若我已经把<tt class="literal">statusChange</tt>集合映射为一个列表而不是一个集合的话,查询写起来会简单很多。 </p><pre class="programlisting">select count(payment), status.name from Payment as payment join payment.currentStatus as statuswhere payment.status.name <> PaymentStatus.AWAITING_APPROVAL or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUsergroup by status.name, status.sortOrderorder by status.sortOrder</pre><p> 下面的查询使用了MS SQL Server的<tt class="literal">isNull()</tt>函数,返回当前用户所属的组织所有账户和未付支出。翻译为SQL查询后,在<tt class="literal">ACCOUNT</tt>, <tt class="literal">PAYMENT</tt>, <tt class="literal">PAYMENT_STATUS</tt>,<tt class="literal">ACCOUNT_TYPE</tt>, <tt class="literal">ORGANIZATION</tt> 和 <tt class="literal">ORG_USER</tt>表之间有三个内部连接,一个外部连接和一个子查询。 </p><pre class="programlisting">select account, paymentfrom Account as account left outer join account.payments as paymentwhere :currentUser in elements(account.holder.users) and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)order by account.type.sortOrder, account.accountNumber, payment.dueDate</pre><p> 对某些数据库而言,我们可能不能依赖(关联的)子查询。 </p><pre class="programlisting">select account, paymentfrom Account as account join account.holder.users as user left outer join account.payments as paymentwhere :currentUser = user and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)order by account.type.sortOrder, account.accountNumber, payment.dueDate</pre></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="queryhql-tipstricks"></a>11.13. 提示和技巧(Tips & Tricks)</h2></div></div><div></div></div><p> 你不返回结果集也可以查询结果集的大小: </p><pre class="programlisting">( (Integer) session.iterate("select count(*) from ....").next() ).intValue()</pre><p> 要依据一个集合的大小对结果集排序,可以用下面的查询来对付一对多或多对多的关联: </p><pre class="programlisting">select usrfrom User as usr left join usr.messages as msggroup by usrorder by count(msg)</pre><p> 如果你的数据库支持子查询,你可以在查询的where子句中对选择的大小进行条件限制: </p><pre class="programlisting">from User usr where size(usr.messages) >= 1</pre><p> 如果你的数据库不支持子查询,可以使用下列查询: </p><pre class="programlisting">select usr.id, usr.namefrom User usr.name join usr.messages msggroup by usr.id, usr.namehaving count(msg) >= 1</pre><p> 因为使用了inner join,这个解决方法不能返回没有message的<tt class="literal">User</tt>.下面的方式就可以: </p><pre class="programlisting">select usrfrom User as usr left join usr.messages as msggroup by usrhaving count(msg) = 0</pre><p> JavaBean的属性可以直接作为命名的查询参数: </p><pre class="programlisting">Query q = s.createQuery("from foo in class Foo where foo.name=:name and foo.size=:size");q.setProperties(fooBean); // fooBean has getName() and getSize()List foos = q.list();</pre><p> 在<tt class="literal">Query</tt>接口中使用过滤器(filter),可以对集合分页: </p><pre class="programlisting">Query q = s.createFilter( collection, "" ); // the trivial filterq.setMaxResults(PAGE_SIZE);q.setFirstResult(PAGE_SIZE * pageNumber);List page = q.list();</pre><p> 集合元素可以使用查询过滤器(query filter)进行排序或者分组: </p><pre class="programlisting">Collection orderedCollection = s.filter( collection, "order by this.amount" );Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );</pre><p> 不用初始化集合就可以得到其大小: </p><pre class="programlisting">( (Integer) session.iterate("select count(*) from ....").next() ).intValue();</pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="transactions.html">上一页</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">上一级</a></td><td width="40%" align="right"> <a accesskey="n" href="querycriteria.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">第 10 章 事务和并行(Transactions And Concurrency) </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> 第 12 章 条件查询(Criteria Query)</td></tr></table></div></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -