【问题标题】:PHP Oracle Pagination Cant Show Data Using ROWNUMPHP Oracle分页无法使用ROWNUM显示数据
【发布时间】:2013-09-24 17:26:17
【问题描述】:

我只是尝试使用 Oracle 数据库,发现分页有问题。 我上次在 MySQL 中使用时效果很好。

查看我的代码:

<?php
$page = $_POST['page'];
$cur_page = $page;
$page -= 1;
$per_page = 3;
$previous_btn = true;
$next_btn = true;
$first_btn = true;
$last_btn = true;
$start = $page * $per_page;

$query_pag_data = "SELECT P.FORM_NO, P.MODEL_NO, P.PRODUCTION_STATUS, P.REMARKS, P.DATE_ADDED, P.TIME, P.QTY_PLAN, M.MODEL_NO, M.MODEL_NAME
                    FROM SEIAPPS_PRODUCTION_STATUS P, SEIAPPS_MODEL M
                    WHERE ROWNUM BETWEEN $start AND $per_page AND P.MODEL_NO = M.MODEL_NO ORDER BY P.DATE_ADDED DESC, P.TIME";

$result_pag_data = oci_parse($c1, $query_pag_data);
oci_execute($result_pag_data);

我使用了 ROWNUM,但是当我想打开第 2 页或下一页时,它没有显示任何数据。而表中还有更多数据。

请大家帮忙指点一下。 谢谢

【问题讨论】:

  • 1) OCI 有oci_bind_by_name 所以请使用它而不是把所有东西都塞进SQL 查询中; 2) 每页 3 个,在第 2 页中,您的 SQL 将是 rownum between 3 and 3,第 3 页,您的 SQL 将是 rownum between 6 and 3
  • @Passerby 的任何例子?

标签: php oracle pagination


【解决方案1】:

Oracle 中的ROWNUM 与 MySQL 中的LIMIT 不同。

MySQL

LIMIT 子句可用于约束SELECT 语句返回的行数...有两个参数,第一个参数指定要返回的第一行的偏移量,第二个指定最大要返回的行数。初始行的偏移量为0(不是1):

SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15

Oracle

对于查询返回的每一行,ROWNUM 伪列返回一个数字,指示 Oracle 从一个表或一组连接行中选择行的顺序。选择的第一行的 ROWNUM 为 1,第二行为 2,依此类推。

SELECT *
  FROM (SELECT * FROM employees ORDER BY employee_id)
  WHERE ROWNUM < 11;

在前面的示例中,ROWNUM 的值是顶级 SELECT 语句的值,因此它们是在子查询中已经按employee_id 对行进行排序之后生成的。

所以你的代码的问题是:

  • WHERE ROWNUM BETWEEN :startrow AND :perpage 在逻辑上不正确,因为ROWNUM 是行索引指示符,而不是“行数”指示符。 ROWNUM BETWEEN a AND b 表示返回从 a 到 b 排序的行,例如第 1 行到第 3 行,NOT 第 1 行和第 3 行。

    因此,即使ROWNUM BETWEEN a AND b 有效(实际上无效),要获取查询的“第 2 页”,从逻辑上讲,您需要 ROWNUM BETWEEN :startrow AND :endrow,例如ROWNUM BETWEEN 4 AND 6;

  • ROWNUM BETWEEN :startrow AND :endrow 实际上不适用于大于 1 的起始行,因为ROWNUM 是一个伪列,表示所选集中行的顺序

    所以当你执行例如SELECT...WHERE ROWNUM BETWEEN 4 AND 6,

    • 第一场比赛,Oracle 认为,“rownum 会在 4 到 6 之间吗?”因为还没有被选中的行,它的ROWNUM会是1如果选中,所以Oracle放弃它;
    • 第二场比赛,“这会是 4 到 6 场吗?”否,因为没有选择任何行,所以这仍然是 1;
    • 第三场比赛,相同;
    • ...

    根本不会有结果。

    要获得所需的输出,您必须将查询包装在子查询中,并检查外部的行号,如下所示:

SELECT * FROM
  (SELECT ROWNUM rn, t.*
    FROM
      (SELECT ...
        FROM ...
        WHERE ...
        ORDER BY ...) t
  )
  WHERE rn>=:startrow AND rn<=:endrow

保证在检查行顺序之前确定行顺序。

  • 关于编码风格,由于 OCI 支持 prepared statementvariable binding,您应该使用它:

    绑定允许数据库重用语句上下文和先前执行语句的缓存,...绑定减少了 SQL 注入问题,因为与绑定变量关联的数据永远不会被视为 SQL 语句的一部分。

$statement=oci_parse("... WHERE rn>=:start AND rn<=:end");
oci_bind_by_name($statement,":start",$start,-1,SQLT_INT);
oci_bind_by_name($statement,":end",intval($start+$per_page-1),-1,SQLT_INT);
oci_execute($statement);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    • 2014-03-21
    • 1970-01-01
    • 2016-10-23
    • 1970-01-01
    相关资源
    最近更新 更多