简体   繁体   English

如何调用Codeigniters 2 Active Record从同一查询中获取2组结果?

[英]How do I call Codeigniters 2 Active record to get 2 sets of results from the same query?

I am essentially creating a chunking function for a file export, and I have a select->from->where that I have built already. 我本质上是在为文件导出创建分块功能,并且我已经在其中建立了select-> from->。 I want to be able to call 'get' twice each time with different limit/offset values. 我希望每次可以使用不同的限制/偏移值两次调用“ get”。

Here's a walk-through of the basic idea. 这是基本概念的演练。

// BallReport.php
function ProcessData(){
    //Report 1
    $query = createSelectQuery();
    $query = applyReportOneWhereValues($query);
    $results1 = CSVTool::processLargeDataSet($query, 10, 1000);

    //Report 2
    $query = createSelectQuery();
    $query = applyReportTwoWhereValues($query);
    $results2 = CSVTool::processLargeDataSet($query, 10, 1000);
}

function createSelectQuery(){
    // the select is complicated having multiple joins and sub queries 
    // so I only want to have to write this once
    $query = $this->db->select('ball.name,
            color.name,
            size.name,
            shape.name')
        ->from('ball')
        ->join('color', 'ball.color_id = color.id')
        ->join('size', 'ball.size_id = size.id')
        ->join('shape', 'ball.shape_id = shape.id');
    return $query;
}

function applyReportOneWhereValues($query){
    // I have 2 different sets of where parameters
    // But they are both using the same select
    // so I separated them into these functions
    // So I can apply the set of where statements
    // all at once
    $query = $query->where("table.color", "blue")
                   ->where("table.size" , "large")
                   ->where("table.shape", "round");
    return $query;
}

function applyReportTwoWhereValues($query){
    $query = $query->where("table.color", "red")
                   ->where("table.size" , "small")
                   ->where("table.shape", "round");
    return $query;
}

//In CSVTool.php 
public static function processLargeDataSet($query, $numberOfPages, $chunkSize){
    // Since the data set is going to be so large we want to process in chunks 
    // So that we don't hit the limit and break mid way. 
    // To do that we only call the DB in sets of 1000 rows
    for(int $i = 0; $i <= $numberOfPages: $i++){
        processRows($query, $i * $chunkSize, $chunkSize);
    }
}

function processRows($query, $offset, $limit){
    // We limit in here so each time it's called we change the offset and limit
    $query = $query->offset($offset)->limit($limit);
    $valuesToProcess = $query->get()->result_array();

    // process the rows here
}

this of course doesn't work because once processRows calls $query->get() the first time all subsequent calls throws a Query error: No tables used 这当然是行不通的,因为一旦processRows第一次调用$ query-> get(),所有后续调用都将引发Query error: No tables used

Is there any solution for this? 有什么解决办法吗? Is there a chunking function in Codeigniter 2 that I'm unaware of? 我没有意识到Codeigniter 2中的分块功能吗?

I think what you are looking for is "Active Record Caching". 我认为您正在寻找的是“活动记录缓存”。 This could be managed from a couple different places. 可以从几个不同的地方进行管理。 In this answer it is in ProcessData() 在这个答案中,它在ProcessData()

Note: You were assigning lots of things to the same var $query and passing it around a lot for no good reason I can see. 注意:您正在为相同的var $query分配很多东西,并且在没有充分理由的情况下将其大量传递。 And you are often overwriting $query with the exact same value multiple times in a row. 而且,您经常连续多次用完全相同的值覆盖$query I have used $this->db in most of the places you used $query . 我在您使用$query大多数地方都使用过$this->db

public function ProcessData()
{
    //Report 1
    $this->db->start_cache();
    //createSelectQuery(); not needed if you want all fields from one table
    applyReportOneWhereValues();
    $this->db->stop_cache();
    processLargeDataSet(10, 1000);

    //Report 2
    $this->db->flush_cache()
    $this->db->start_cache();
    //createSelectQuery(); not needed if you want all fields from one table
    applyReportTwoWhereValues();
    $this->db->stop_cache();
    processLargeDataSet(10, 1000);
    $this->db->flush_cache();
}

Your question uses select("*") and from("table_name") which can be eliminated if you really want all fields from one table. 您的问题使用select("*")from("table_name") ,如果您确实希望从一个表中获取所有字段,可以将其删除。 When get("table_name") is used and there is no select() call then all fields are assumed. 当使用get("table_name")且没有select()调用时,则假定所有字段。 IOW, the query statement would be SELECT * FROM 'table_name'; IOW,查询语句为SELECT * FROM 'table_name';

Based on the question's code it seems you don't need the createSelectQuery() function. 根据问题的代码,您似乎不需要createSelectQuery()函数。

Your "apply where" functions but re-written using method chaining. 您的“应用在哪里”功能起作用,但使用方法链重写。

public function applyReportOneWhereValues()
{
    $this->db
      ->where("table.color", "blue")
      ->where("table.size", "large")
      ->where("table.shape", "round");
}

public function applyReportTwoWhereValues()
{
    $this->db
      ->where("table.color", "red")
      ->where("table.size", "small")
      ->where("table.shape", "round");
}

I have eliminated processRows() and incorporated that logic into processLargeDataSet() . 我消除了processRows()并将该逻辑合并到processLargeDataSet() Notice how get() is used - passing a table name, limit, and offset - to remove the need for select() , from() , limit() , and offset() calls. 注意get()的用法-传递表名,限制和偏移量-消除了对select()from()limit()offset()调用的需要。

/**
 * Process the records in chunks
 * @param int $numberOfPages The number of pages to create in the set (1 to n)
 * @param int $pageSize The number of records per page
 */
function processLargeDataSet($numberOfPages, $pageSize)
{
    if($numberOfPages < 1)
    {
        $numberOfPages = 1;
    }
    for($i = 1; $i < $numberOfPages; $i++)
    {
        $valuesToProcess = $this->db
          ->get('table', $pageSize, ($i-1) * $pageSize)
          ->result_array();
        // process the rows in $valuesToProcess
    }
}

Here is a new answer to the revised question. 这是对修订后的问题的新答案。

public function ProcessData()
{
    //Report 1
    $query_builder = $this->applyReportOneWhereValues($this->createSelectQuery());
    $this->db->stop_cache();
    $results1 = CSVTool::processLargeDataSet($query_builder, 10, 1000);
    $this->db->flush_cache();

    //Report 2
    $query_builder = $this->applyReportTwoWhereValues($this->createSelectQuery());
    $this->db->stop_cache();
    $results2 = CSVTool::processLargeDataSet($query_builder, 10, 1000);
    $this->db->flush_cache(); //just to be safe
}

public function createSelectQuery()
{
    $this->db->start_cache();
    return $this->db->select('ball.name, color.name, size.name, shape.name')
        ->join('color', 'ball.color_id = color.id')
        ->join('size', 'ball.size_id = size.id')
        ->join('shape', 'ball.shape_id = shape.id');
}

public function applyReportOneWhereValues($query_builder)
{
    return $query_builder
      ->where("table.color", "blue")
      ->where("table.size", "large")
      ->where("table.shape", "round");
}

public function applyReportTwoWhereValues($query_builder)
{
    return $query_builder
      ->where("table.color", "red")
      ->where("table.size", "small")
      ->where("table.shape", "round");
}

In CSVTool.php 在CSVTool.php中

/**
 * Process the records in chunks
 * @param CI_DB_query_builder $qb An instance of the CI_DB_query_builder class
 * @param int $numberOfPages The number of pages to create in the set (1 to n)
 * @param int $pageSize The number of records per page
 */
public static function processLargeDataSet($qb, $numberOfPages, $pageSize)
{
    if($numberOfPages < 1)
    {
        $numberOfPages = 1;
    }
    for($i = 1; $i < $numberOfPages; $i++)
    {
        $valuesToProcess = $qb
          ->get('ball', $pageSize, $i - 1 * $pageSize)
          ->result_array();
        // process the rows in $valuesToProcess
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM