【问题标题】:Zend_Db_Adapter_Oracle: Select with ORDER BY, LIMIT & WHEREZend_Db_Adapter Oracle:使用 ORDER BY、LIMIT 和 WHERE 进行选择
【发布时间】:2013-02-06 12:18:36
【问题描述】:

我正在尝试从 Oracle 11g 数据库中选择一些记录。该语句用于为 HTML 表格实现某种“过滤”功能。

要求:分页限制和过滤结果排序。

查询是用 Zend_Db_Select

创建的

*像魅力一样工作:*

$select->where('APPLICATIONS LIKE ?', '%MYAPP1%');
$select->where('APPLICATIONS NOT LIKE ?', '%GENESIS%');
$select->limit(20);

= 1 个匹配结果(没关系!)

当我尝试排序过滤结果时出现问题:

$select->order('PATH ASC');

= 3 个匹配结果 ??

我认为这与 Zend DB Select 生成的查询有关,它看起来像这样:

 SELECT z2.*
    FROM (
        SELECT z1.*, ROWNUM AS "zend_db_rownum"
        FROM (
            SELECT "APPS".* FROM "APPS" WHERE (APPLICATIONS LIKE '%MYAPP1%') AND (APPLICATIONS NOT LIKE '%GENESIS%') ORDER BY "PATH" ASC
        ) z1
    ) z2
    WHERE z2."zend_db_rownum" BETWEEN 1 AND 20
  • 如果我不按顺序运行查询,一切都很好。
  • 如果我无限制地运行查询,一切都很好。
  • 如果我使用 order + limit 运行查询 -> 错误结果。

如果我接受声明并将订单放在“BETWEEN 1 AND 20”之后,它会像我想要的那样工作。但是 Zend DB Select 怎么改呢?

重要提示:我正在对 Oracle VIEW 进行查询,如果我对“表”进行查询,它也可以。

【问题讨论】:

    标签: php sql oracle zend-framework


    【解决方案1】:

    如果您检查SQL生成没有错误,并且WHERE子句确实没有不同的条件,则可能是Oracle服务器错误。要检查它,请在不同的 Oracle 服务器版本或不同的 Oracle 服务器补丁级别上尝试。

    【讨论】:

    • 当然问题是订单在“子选择”中,如果 zend 将订单放在最后它会起作用(;
    • 在此 SQL 中,ORDER BY 不能超出 - ROWNUM 需要在已排序的行上实现。你能准备或问一些不同的Oracle版本吗?如果可以更改 SQL,可以使用 row_number() 窗口函数更改 ROWNUM ?
    • igr:能否详细解释一下?
    • 有关 ROWNUM docs.oracle.com/cd/E11882_01/server.112/e26088/… 的更多详细信息。有关 row_number() 的更多信息,请参见页面开头的链接。请注意,文档适用于 11.2 - 如果您的服务器版本不同,请参阅另一个版本
    • 重要:我正在对 Oracle VIEW 进行查询,如果我对“表”进行查询,它也可以..
    【解决方案2】:

    显然,Oracle 对查询的解释不是 Zend 框架的意图: Oracle 似乎在排序之前将 ROWNUM 与 内部查询 上的行号计数相关联,因此别名 zend_db_rownum 在 外部查询的 where 子句中提供了错误的数字.

    由于我们无法控制 Zend 框架生成 SQL 以响应 limit() 指令的方式,所以我能想到的唯一解决方法是跳过 Zend limit() 指令,而是按照以下方式做一些事情:

    $select->where('APPLICATIONS LIKE ?', '%MYAPP1%');
    $select->where('APPLICATIONS NOT LIKE ?', '%GENESIS%');
    $select->order('PATH ASC');
    
    $sql = $select->__toString();
    
    $sql = "select * from (" . $sql . ") where ROWNUM between 1 and 20";
    
    $stmt = $db->query( $sql, array());
    $result = $stmt->fetchAll();
    

    当然,此解决方法在您开发跨数据库的情况下是合法的,因此您的代码不必与数据库不可知。 这意味着,如果您使用我建议的解决方法,您的解决方案将仅限于 Oracle。

    【讨论】:

    • 我已经实现了一些类似的东西(将 SQL 转换为字符串并将顺序添加到末尾),但您的建议看起来更好。谢谢
    猜你喜欢
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多