【发布时间】:2015-01-06 19:06:36
【问题描述】:
我正在开发一个 Oracle/PHP 应用程序并尝试实现“加载更多”功能。
这是两个表及其结构:
questions:
id (int) | title (varchar(999)) | datetime (varchar(999))
questions_tags:
id (int) | question_id (int) | tag_id (int)
以下是index.php中的代码:
$stid = oci_parse($conn, "select * from (
select a.*, ROWNUM rnum from (
SELECT questions.id FROM questions_tags, questions WHERE
questions.id = questions_tags.question_id AND
questions_tags.tag_id IN (1,2,3,4,5,6,7) ORDER BY questions.datetime ASC
) a where rownum <= 10
) where rnum >= 0");
oci_execute($stid);
while (oci_fetch($stid)) {
// Do work with the results
}
下面是它背后的javascript:
$("#load_more").click(function(e) {
$.ajax({
url: "loadMore.php?x=" + $(".span_data:last").data("id"),
success:function(data, textStatus, jqXHR)
{
if (data)
{
// append data
} else {
// remove button
}
},
error: function(jqXHR, textStatus, errorThrown)
{
//if fails
}
});
e.preventDefault(); //STOP default action
});
最后,这里是 loadMore.php 文件:
<?php
$x = $_GET['x'];
$xTen = intval($x) + 10;
$count_id = $x;
try
{
$lastID = 0;
$tagIDs = implode("','", $user_tag_ids);
$stid = oci_parse($conn, "select * from (
select a.*, ROWNUM rnum from (
SELECT questions.id FROM questions_tags, questions WHERE
questions.id = questions_tags.question_id AND
questions_tags.tag_id IN (1,2,3,4,5,6,7) ORDER by questions.datetime DESC
) a where rownum <= $xTen
) where rnum >= $x");
oci_execute($stid);
while (oci_fetch($stid)) {
// Do work with the results
}
}
catch(Exception $e) {
print "Error";
}
?>
无论x 的值是多少,loadMore.php 文件都会继续返回相同的结果集。因此,如果我执行/loadMore.php?x=10,我将得到与/loadMore.php?x=100 返回的结果相同的结果。但是,如果我走得更远(/loadMore.php?x=1500),那是我最终得到不同结果的时候。我不明白这里出了什么问题。
正如我在 cmets 中所说的:
如果我删除所有rownum 参数并运行
SELECT * FROM questions WHERE EXISTS (
SELECT 1 FROM questions_tags WHERE
questions.id = questions_tags.question_id AND
questions_tags.tag_id IN (1,2,3,4,5,6,7)
) ORDER BY datetime DESC
我得到了所有结果,可能有一千行。我试图获取这千行中的前 10 行,然后当用户单击“加载更多”按钮时继续获取下 10 行。这就是为什么我有相同的查询 index.php 和 loadMore.php
【问题讨论】:
-
questions.datetime是唯一的吗?如果您的ORDER BY没有生成唯一的订单,那么即使使用相同的参数,一行也完全有可能在后续执行中得到不同的ROWNUM。换句话说,如果“前 10 个”没有明确定义,因为有数百行具有相同的datetime值,那么您的方法将无法正常工作。 -
datetime不是唯一的。如果我删除所有 rownum 参数并只运行SELECT * FROM questions WHERE EXISTS (SELECT 1 FROM questions_tags WHERE questions.id = questions_tags.question_id AND questions_tags.tag_id IN ('$tagIDs'))ORDER BY datetime DESC查询,我会得到所有结果,可能有一千行。我非常想做的是获取这千行中的前 10 行,然后在用户单击“加载更多”按钮时继续获取下 10 行。这就是为什么我有相同的查询index.php和loadMore.php -
如果您想要一个可以依赖的排序,那么您需要在 ORDER BY 子句中包含足够多的列,以便所有这些列的组合对于每一行都是唯一的。没有其他保证。
-
您可能会摆脱最外层的查询,并在第一个内部查询中使用
WHERE rownum BETWEEN $x and $xTen之类的内容。另外,sql注入警告。加 10 时你 intval $x ,但在获得初始值时不是。最后,这将返回 11 行,而不是 10 行。您可能希望从$xTen中减去 1 或将<= $xTen切换为< $xTen。将>=留在$x比较中。 -
只是阅读,我看到你正在做的方式应该是最佳解决方案。我整天都在使用 Oracle,但有一段时间不用在其中进行分页了,因为我们通常没有大型列表。