2012-09-06 90 views
6

我在VisualWorks和Oracle数据库中使用Glorp。由于Oracle不知道LIMIT命令,因此以下查询返回全部其中WHERE子句评估为true的myTable的记录。Glorp和Oracle:限制查询结果

q := Glorp.SimpleQuery 
     returningManyOf: MyTable 
     where: [:each | each name = 'test'] 
     limit: 10. 
q orderBy: [:each | each id descending]. 
results:= aGlorpSession execute: q. 

我该如何将ROWNUM纳入此Glorp查询?

//编辑生成的SQL:

SELECT t1.id, t1.name 
FROM MyTable t1 
WHERE (t1.name= ?) ORDER BY t1.id DESC 
+0

限制Oracle中行数的常用方法是select * from(select ... order by ...)其中rownum <10。是否可以修改由Glorp生成的查询? –

+0

是的,应该提到我知道如何在Oracle中做到这一点。我只是不知道如何在格洛普做到这一点。 – Cantillon

+0

Glorp在使用Oracle时是否在后台使用游标,还是实际将内存中的所有结果都提取出来? –

回答

1

在Smalltalk.Glorp.DatabasePlatform我添加了两个空的方法#printPreLimitWrapper:上:与#printPostLimitWrapper:上:这是我在Smalltalk.Glorp.OraclePlatform覆盖:

printPreLimitWrapper: anInteger on: aCommand 
    aCommand nextPutAll: ' SELECT * FROM (' 

printPostLimitWrapper: anInteger on: aCommand 

    aCommand nextPutAll: ') WHERE ROWNUM <= '. 
    anInteger printOn: aCommand. 
    aCommand nextPutAll: ' '. 

在Smalltalk.Glorp.SimpleQuery我补充:

printPostLimitWrapperOn: aCommand 
    self hasLimit ifFalse: [^self]. 
    self platform printPostLimitWrapper: self limit on: aCommand. 

printPreLimitWrapperOn: aCommand 
    self hasLimit ifFalse: [^self]. 
    self platform printPreLimitWrapper: self limit on: aCommand. 

而且在Smalltalk.Glorp.QuerySelectCommand我改变了下面的方法:

printSQL 
    query printPreLimitWrapperOn: self. 
    stream nextPutAll: 'SELECT '. 
    query printSelectFieldsOn: self. 
    self findBoundExpressions. 
    query printTablesOn: self. 
    query printWhereClauseOn: self. 
    query printJoinsOn: self. 
    query printOrderingOn: self. 
    query printGroupByOn: self. 
    query printPostLimitOn: self. 
    query printOffsetOn: self. 
    query printPostLimitWrapperOn: self. 
1

即使你可以添加ROWNUM到这个查询,你可能仍然不能得到你想要的结果。问题在于WHERE子句在ORDER BY之前应用 - 因此,通过限制返回的前10行,您将获得这10行,然后它们将被排序。这里有一个例子:

CREATE TABLE order_test(seq_num NUMBER); 

INSERT INTO order_test(seq_num) VALUES(20); 
INSERT INTO order_test(seq_num) VALUES(19); 
INSERT INTO order_test(seq_num) VALUES(18); 
INSERT INTO order_test(seq_num) VALUES(17); 
INSERT INTO order_test(seq_num) VALUES(16); 
INSERT INTO order_test(seq_num) VALUES(15); 
INSERT INTO order_test(seq_num) VALUES(14); 
INSERT INTO order_test(seq_num) VALUES(13); 
INSERT INTO order_test(seq_num) VALUES(12); 
INSERT INTO order_test(seq_num) VALUES(11); 
INSERT INTO order_test(seq_num) VALUES(10); 
INSERT INTO order_test(seq_num) VALUES(09); 
INSERT INTO order_test(seq_num) VALUES(08); 
INSERT INTO order_test(seq_num) VALUES(07); 
INSERT INTO order_test(seq_num) VALUES(06); 
INSERT INTO order_test(seq_num) VALUES(05); 
INSERT INTO order_test(seq_num) VALUES(04); 
INSERT INTO order_test(seq_num) VALUES(03); 
INSERT INTO order_test(seq_num) VALUES(02); 
INSERT INTO order_test(seq_num) VALUES(01); 

SELECT * FROM order_test WHERE ROWNUM < 10 ORDER BY seq_num; 

查询我的系统上返回

12 
13 
14 
15 
16 
17 
18 
19 
20 

。我怀疑你想要什么是

SELECT * 
    FROM (SELECT * FROM ORDER_TEST ORDER BY SEQ_NUM) 
    WHERE ROWNUM < 10 

返回1到9

相当于我不知道是否或如何在Glorp嵌套查询。 (FWIW--我知道并且喜欢Smalltalk,但是因为这样的原因,我讨厌持久性框架)。 YMMV,显然。

(顺便说一句 - 您可能会修改Glorp.SimpleQuery上的#limit:方法,将比较ROWNUM注入到WHERE子句中 - 但正如我上面所说的,结果可能仍然会不是什么意图,一个实现留给感兴趣的读者来做一个练习:-)。

分享和享受。

1

首先,我建议不同的语法 Glorp.Query阅读:... 你不是真的想在前面指定SimpleQuery类,并阅读:比returningManyOf更短:和将完成一样。

我目前没有软件在我面前,但我很肯定在Oracle上limit:命令应该转化为使用rownum。你看到这些会产生什么SQL?

+0

好的,我会用read :.写入限制委托给数据库平台。默认实现是空的,并且仅仅为PostgreSQLPlatform和SQLServerPlatform实现。我将生成的SQL添加到原始问题中。 – Cantillon