如何在运行查询之前使用get_compiled_select或count_all_results而不将表名添加两次?当我在这两个命令之后使用$this-〉db-〉get('tblName')时,我得到错误:
Not unique table/alias: 'tblProgram'
SELECT * FROM (`tblProgram`, `tblProgram`) JOIN `tblPlots` ON `tblPlots`.`programID`=`tblProgram`.`pkProgramID` JOIN `tblTrees` ON `tblTrees`.`treePlotID`=`tblPlots`.`id` ORDER BY `tblTrees`.`id` ASC LIMIT 2000
如果我没有在count_all_results或$this-〉db-〉get()中使用表名,那么我会得到一个没有使用表的错误。我如何让它只设置一次表名呢?
public function get_download_tree_data($options=array(), $rand=""){
//join tables and order by tree id
$this->db->reset_query();
$this->db->join('tblPlots','tblPlots.programID=tblProgram.pkProgramID');
$this->db->join('tblTrees','tblTrees.treePlotID=tblPlots.id');
$this->db->order_by('tblTrees.id', 'ASC');
//get number of results to return
$allResults=$this->db->count_all_results('tblProgram', false);
//chunk data and write to CSV to avoid reaching memory limit
$offset=0;
$chunk=2000;
$treePath=$this->config->item('temp_path')."$rand/trees.csv";
$tree_handle=fopen($treePath,'a');
while (($offset<$allResults)) {
$this->db->limit($chunk, $offset);
$result=$this->db->get('tblProgram')->result_array();
foreach ($result as $row) {
fputcsv($tree_handle, $row);
}
$offset=$offset+$chunk;
}
fclose($tree_handle);
return array('resultCount'=>$allResults);
}
4条答案
按热度按时间yvfmudvl1#
要计算一个查询 * 将 * 返回多少行,基本上必须执行所有的工作。也就是说,获得计数,然后执行查询是不切实际的;您还不如直接执行查询。
如果您的目标是通过获取一些行加上总数来“分页”,那么这实际上是两个独立的操作(可以组合起来看起来像一个操作)。
如果目标是 * 估计 * 行数,则
SHOW TABLE STATUS
或SELECT
RowsFROM information_schema.TABLES WHERE ...
会为您提供 * 估计 *。如果你想看看是否有,比如说“至少100行”,那么这可能是实用的:
然后看看是否返回了一行。但是,这可能 * 也可能 * 不是有效的,这取决于索引以及
WHERE
和ORDER BY
。(向我们展示查询,我可以详细说明。)使用
OFFSET
进行分块是非常低效的。如果没有可用的索引,那么它实际上是在为每个块执行整个查询。如果有可用的索引,那么块的速度会越来越慢。下面讨论为什么OFFSET
不适合“分页”,以及一个有效的解决方案:Pagination。它讲述了如何“记住你离开的地方“作为一种有效的分块技术。每个分块取100到1000行。x6h2sr282#
您代码中的缺陷在于,它的目的是在同一个查询中选择一些记录的子集及其总数。这在MySQL中是不可能的,因此您无法生成这样的查询,因此,您会得到上面提到的错误。问题是,如果您执行
则您将获得最多2000条记录,因此,如果匹配条件的记录总数大于限制,则您将无法从上面的示例中准确获得计数,因此,在这种情况下,您需要
这意味着您需要构建实际的查询(
count_all_results
调用下面的代码),查看结果数是否达到限制。如果结果数未达到限制,则不需要执行单独的查询来获取计数,因为您可以计算$offset * $chunk + $recordCount
。但是,如果获取尽可能多的记录,那么您将需要构建另一个查询,但不使用order_by
调用,因为计数与排序无关,并获取计数。egdjgwm83#
$this-〉数据库-〉所有结果计数()
使用
count_all_results()
计算返回的结果数计算返回结果的数量是很有用的--如果一段代码中至少有一行被传递了零行,通常会出现错误。如果不处理零结果的可能性,应用程序可能会变得不可预测的不稳定,并可能向恶意用户给予有关应用程序架构的提示。确保正确处理零结果是我们在这里要重点关注的。
允许您确定特定活动记录查询中的行数。查询将接受查询生成器限制器,如where()或_where()、like()或_like()等。示例:
不过,此方法也会重设您传递给select()的任何字段值。如果您需要保留这些值,可以传递FALSE做为第二个参数:
获取编译的选择()
codeigniter v3.0中引入了方法
$this->db->get_compiled_select();
,它编译活动记录查询而不实际执行它。但这不是一个全新的方法。在CI的旧版本中,它类似于$this->db->_compile_select();
,但在更高版本中,该方法已被保护,使其无法回调。**注意:-**当您使用Query Builder Caching功能并且不重置您的查询时,对
get_compiled_select()
的两次调用将导致该高速缓存合并两次。这反过来会导致,如果您正在缓存select()-,则会选择同一字段两次。8i9zcol24#
Rick James让我走上了正确的道路。最后我不得不使用分页和嵌套查询对结果进行分块。在2000条记录中,即使有一条记录使用LIMIT也会超时。这是我最终得到的代码,它使用get_compiled_select('tblProgram '),然后获取因为我没有使用FALSE作为get_compiled_select的第二个参数,所以在运行get()之前就清除了查询。