使用 Codeigniter 的活动记录模式进行 UNION 查询

发布于 2024-08-17 09:09:51 字数 47 浏览 7 评论 0原文

如何使用PHP CodeIgniter框架的活动记录查询格式进行UNION查询?

How to do UNION query with PHP CodeIgniter framework's active record query format?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

忘羡 2024-08-24 09:09:52

CodeIgniter 的 ActiveRecord 不支持 UNION,因此您只需编写查询并使用 ActiveRecord 的查询方法即可。

$this->db->query('SELECT column_name(s) FROM table_name1 UNION SELECT column_name(s) FROM table_name2');

CodeIgniter's ActiveRecord doesn't support UNION, so you would just write your query and use the ActiveRecord's query method.

$this->db->query('SELECT column_name(s) FROM table_name1 UNION SELECT column_name(s) FROM table_name2');
浊酒尽余欢 2024-08-24 09:09:52

通过使用last_query()进行联合,可能会影响应用程序的性能。因为对于单个联合,需要执行 3 个查询。即对于“n”联合“n+1”查询。对于 1-2 查询联合不会有太大影响。但如果联合多个查询或具有大数据的表,则会出现问题。

此链接将为您提供很大帮助: 活动记录子查询

我们可以将活动记录与手动查询结合起来。
例子:

// #1 SubQueries no.1 -------------------------------------------

$this->db->select('title, content, date');
$this->db->from('mytable');
$query = $this->db->get();
$subQuery1 = $this->db->_compile_select();

$this->db->_reset_select();

// #2 SubQueries no.2 -------------------------------------------

$this->db->select('title, content, date');
$this->db->from('mytable2');
$query = $this->db->get();
$subQuery2 = $this->db->_compile_select();

$this->db->_reset_select();

// #3 Union with Simple Manual Queries --------------------------

$this->db->query("select * from ($subQuery1 UNION $subQuery2) as unionTable");

// #3 (alternative) Union with another Active Record ------------

$this->db->from("($subQuery1 UNION $subQuery2)");
$this->db->get();

By doing union using last_query(), it may hamper performance of application. Because for single union it would require to execute 3 queries. i.e for "n" union "n+1" queries. It won't much affect for 1-2 query union. But it will give problem if union of many queries or tables having large data.

This link will help you a lot: active record subqueries

We can combine active record with manual queries.
Example:

// #1 SubQueries no.1 -------------------------------------------

$this->db->select('title, content, date');
$this->db->from('mytable');
$query = $this->db->get();
$subQuery1 = $this->db->_compile_select();

$this->db->_reset_select();

// #2 SubQueries no.2 -------------------------------------------

$this->db->select('title, content, date');
$this->db->from('mytable2');
$query = $this->db->get();
$subQuery2 = $this->db->_compile_select();

$this->db->_reset_select();

// #3 Union with Simple Manual Queries --------------------------

$this->db->query("select * from ($subQuery1 UNION $subQuery2) as unionTable");

// #3 (alternative) Union with another Active Record ------------

$this->db->from("($subQuery1 UNION $subQuery2)");
$this->db->get();
此生挚爱伱 2024-08-24 09:09:52

这是我曾经使用过的一种快速而肮脏的方法,

// Query #1

$this->db->select('title, content, date');
$this->db->from('mytable1');
$query1 = $this->db->get()->result();

// Query #2

$this->db->select('title, content, date');
$this->db->from('mytable2');
$query2 = $this->db->get()->result();

// Merge both query results

$query = array_merge($query1, $query2);

不是我最好的作品,但它解决了我的问题。

注意:我不需要订购结果。

This is a quick and dirty method I once used

// Query #1

$this->db->select('title, content, date');
$this->db->from('mytable1');
$query1 = $this->db->get()->result();

// Query #2

$this->db->select('title, content, date');
$this->db->from('mytable2');
$query2 = $this->db->get()->result();

// Merge both query results

$query = array_merge($query1, $query2);

Not my finest work, but it solved my problem.

note: I didn't need to order the result.

感情废物 2024-08-24 09:09:52

您可以使用以下方法来获取模型中的 SQL 语句:

$this->db->select('DISTINCT(user_id)');
$this->db->from('users_master');
$this->db->where('role_id', '1');

$subquery = $this->db->_compile_select();
$this->db->_reset_select();

这样 SQL 语句将位于 $subquery 变量中,而不是实际执行它。

你很久以前就问过这个问题,所以也许你已经有了答案。如果没有,这个过程可能会成功。

You may use the following method to get the SQL statement in the model:

$this->db->select('DISTINCT(user_id)');
$this->db->from('users_master');
$this->db->where('role_id', '1');

$subquery = $this->db->_compile_select();
$this->db->_reset_select();

This way the SQL statement will be in the $subquery variable, without actually executing it.

You have asked this question a long time ago, so maybe you have already got the answer. if not, this process may do the trick.

素手挽清风 2024-08-24 09:09:52

通过修改 somnath huluks 答案,我将以下变量和函数添加到 DB_Active_rec 类中,如下所示:

class DB_Active_records extends CI_DB_Driver
{

   ....

   var $unions;

   ....

    public function union_push($table = '')
    {
        if ($table != '')
        {
            $this->_track_aliases($table);
            $this->from($table);
        }

        $sql = $this->_compile_select();

        array_push($this->unions, $sql);
        $this->_reset_select();
    }

    public function union_flush()
    {
        $this->unions = array();
    }

    public function union()
    {
        $sql = '('.implode(') union (', $this->unions).')';
        $result = $this->query($sql);
        $this->union_flush();
        return $result;
    }

    public function union_all()
    {
        $sql = '('.implode(') union all (', $this->unions).')';
        $result = $this->query($sql);
        $this->union_flush();
        return $result;
    }
}

因此您实际上可以使用联合,而不依赖于 db_driver。

要将此方法与 union 结合使用,您只需进行常规活动记录查询,但调用 union_push 而不是 get。

注意:您必须确保您的查询具有匹配的列,例如常规联合示例

    $this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file');
    $this->db->where(array('l.requirement' => 0));
    $this->db->union_push('lessons l');
    $this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file');
    $this->db->from('lessons l');
    $this->db->join('scores s', 'l.requirement = s.lid');
    $this->db->union_push();
    $query = $this->db->union_all();
    return $query->result_array();

将产生:

(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file`
FROM `lessons` l
WHERE `l`.`requirement`=0)
union all 
(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file`
FROM `lessons` l
JOIN `scores` s ON `l`.`requirement`=`s`.`lid`)

by modifying somnath huluks answer, i add these following variable and functions to DB_Active_rec class as follows:

class DB_Active_records extends CI_DB_Driver
{

   ....

   var $unions;

   ....

    public function union_push($table = '')
    {
        if ($table != '')
        {
            $this->_track_aliases($table);
            $this->from($table);
        }

        $sql = $this->_compile_select();

        array_push($this->unions, $sql);
        $this->_reset_select();
    }

    public function union_flush()
    {
        $this->unions = array();
    }

    public function union()
    {
        $sql = '('.implode(') union (', $this->unions).')';
        $result = $this->query($sql);
        $this->union_flush();
        return $result;
    }

    public function union_all()
    {
        $sql = '('.implode(') union all (', $this->unions).')';
        $result = $this->query($sql);
        $this->union_flush();
        return $result;
    }
}

therefore you can virtually use unions without dependencies to db_driver.

to use union with this method, you simply make regular active record queries, but calling union_push instead of get.

note: you have to ensure your queries have matching columns like regular unions

example:

    $this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file');
    $this->db->where(array('l.requirement' => 0));
    $this->db->union_push('lessons l');
    $this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file');
    $this->db->from('lessons l');
    $this->db->join('scores s', 'l.requirement = s.lid');
    $this->db->union_push();
    $query = $this->db->union_all();
    return $query->result_array();

would produce:

(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file`
FROM `lessons` l
WHERE `l`.`requirement`=0)
union all 
(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file`
FROM `lessons` l
JOIN `scores` s ON `l`.`requirement`=`s`.`lid`)
陪你搞怪i 2024-08-24 09:09:52

我找到了这个库,它非常适合我以 ActiveRecord 样式添加 UNION:

https://github.com /NTICompass/CodeIgniter-Subqueries

但我必须首先从 CodeIgniter 的 dev 分支获取 get_compiled_select() 方法(可在此处获取:https://github.com/EllisLab/CodeIgniter/blob/develop/system/database/DB_query_builder.php -- DB_query_builder 将取代 DB_active_rec)。据推测,此方法将在 CodeIgniter 的未来生产版本中提供。

一旦我将该方法添加到系统/数据库中的 DB_active_rec.php 中,它就像一个魅力。 (我不想使用 CodeIgniter 的开发版本,因为这是一个生产应用程序。)

I found this library, which worked nicely for me to add UNION in an ActiveRecord style:

https://github.com/NTICompass/CodeIgniter-Subqueries

BUT I had to grab the get_compiled_select() method from the dev branch of CodeIgniter first (available here: https://github.com/EllisLab/CodeIgniter/blob/develop/system/database/DB_query_builder.php -- DB_query_builder will be replacing DB_active_rec). Presumably this method will be available in a future production release of CodeIgniter.

Once I added that method to DB_active_rec.php in system/database it worked like a charm. (I didn't want to use the dev version of CodeIgniter as this is a production app.)

念三年u 2024-08-24 09:09:52

这是我正在使用的解决方案:

$union_queries = array();
$tables = array('table1','table2'); //As much as you need
foreach($tables as $table){
    $this->db->select(" {$table}.row1, 
                        {$table}.row2,
                        {$table}.row3");
    $this->db->from($table);
    //I have additional join too (removed from this example)
    $this->db->where('row4',1);
    $union_queries[] = $this->db->get_compiled_select();
}
$union_query = join(' UNION ALL ',$union_queries); // I use UNION ALL
$union_query .= " ORDER BY row1 DESC LIMIT 0,10";
$query = $this->db->query($union_query);

This is solution I am using:

$union_queries = array();
$tables = array('table1','table2'); //As much as you need
foreach($tables as $table){
    $this->db->select(" {$table}.row1, 
                        {$table}.row2,
                        {$table}.row3");
    $this->db->from($table);
    //I have additional join too (removed from this example)
    $this->db->where('row4',1);
    $union_queries[] = $this->db->get_compiled_select();
}
$union_query = join(' UNION ALL ',$union_queries); // I use UNION ALL
$union_query .= " ORDER BY row1 DESC LIMIT 0,10";
$query = $this->db->query($union_query);
时光倒影 2024-08-24 09:09:52

试试这个

function get_merged_result($ids){                   
    $this->db->select("column");
    $this->db->distinct();
    $this->db->from("table_name");
    $this->db->where_in("id",$model_ids);
    $this->db->get(); 
    $query1 = $this->db->last_query();

    $this->db->select("column2 as column");
    $this->db->distinct();
    $this->db->from("table_name");
    $this->db->where_in("id",$model_ids);

    $this->db->get(); 
    $query2 =  $this->db->last_query();
    $query = $this->db->query($query1." UNION ".$query2);

    return $query->result();
}

try this one

function get_merged_result($ids){                   
    $this->db->select("column");
    $this->db->distinct();
    $this->db->from("table_name");
    $this->db->where_in("id",$model_ids);
    $this->db->get(); 
    $query1 = $this->db->last_query();

    $this->db->select("column2 as column");
    $this->db->distinct();
    $this->db->from("table_name");
    $this->db->where_in("id",$model_ids);

    $this->db->get(); 
    $query2 =  $this->db->last_query();
    $query = $this->db->query($query1." UNION ".$query2);

    return $query->result();
}
零度℉ 2024-08-24 09:09:52

bwisn 的答案比所有答案都好,并且可以工作,但性能不佳,因为它会首先执行子查询。
get_compiled_select 不运行查询;它只是编译它以供以后运行,所以速度更快
试试这个

$this->db->select('title, content, date');
$this->db->where('condition',value);
$query1= get_compiled_select("table1",FALSE);
$this->db->reset_query();

$this->db->select('title, content, date');
$this->db->where('condition',value);
$query2= get_compiled_select("table2",FALSE);
$this->db->reset_query();

$query = $this->db->query("$query1 UNION $query2");

bwisn's answer is better than all and will work but not good in performance because it will execute sub queries first.
get_compiled_select does not run query; it just compiles it for later run so is faster
try this one

$this->db->select('title, content, date');
$this->db->where('condition',value);
$query1= get_compiled_select("table1",FALSE);
$this->db->reset_query();

$this->db->select('title, content, date');
$this->db->where('condition',value);
$query2= get_compiled_select("table2",FALSE);
$this->db->reset_query();

$query = $this->db->query("$query1 UNION $query2");
萤火眠眠 2024-08-24 09:09:52

我看到有人问如何通过查询生成器方法将 ORDER BY 与 UNION 结合使用。

只需记住封装您的子查询,以便您的 LIMIT 和 ORDER BY 逻辑按预期执行。

public function demoCompiledUnion(int $param1, int $param2): array
{
    $lows = $this->db
        ->select('pk, address')
        ->from('unit1')
        ->where('pk <', $param1)
        ->limit(5)
        ->get_compiled_select();

    $highs = $this->db
        ->select('pk, address')
        ->from('unit2')
        ->where('pk >', $param2)
        ->limit(5)
        ->get_compiled_select();

    return $this->db  // don't need select() if you want every column
        ->from("($lows) UNION ($highs)")
        ->order_by(2, 'DESC')  // order by address DESC
        ->get()
        ->result();  // return payload as an array of objects
}

我打印了 $this->db->last_query() 并添加了一些选项卡来显示此呈现的 SQL(引用字符可能会根据您的数据库驱动程序/方言而有所不同):

SELECT *
FROM (
    SELECT "pk", "address"
    FROM "unit1"
    WHERE "pk" < 10000
    LIMIT 5
) UNION (
    SELECT "pk", "address"
    FROM "stl_unit"
    WHERE "stl_unit_pk" > 15000
    LIMIT 5
)
ORDER BY 2 DESC

结果集完全相同正如预期的那样——10 行按地址列值降序排序。

由于此查询构建的所有潜在易受攻击的部分都是通过活动记录方法完成的,因此它与 CodeIgniter 所允许的一样安全。


一个重要的额外注意事项:如果您想将 ->where()->like() 或其他一些子句附加到联合 FROM 子句中,您将需要将双表表达式括在外括号中并分配表别名。例如:

return $this->db
    ->from("(($lows) UNION ($highs)) united")
    ->like('address', '1')
    ->order_by(2, 'DESC')
    ->get()
    ->result();

I saw that someone asked how to use ORDER BY with UNION via query builder methods.

Just remember to encapsulate your subqueries so that your LIMIT and ORDER BY logic is executed as intended.

public function demoCompiledUnion(int $param1, int $param2): array
{
    $lows = $this->db
        ->select('pk, address')
        ->from('unit1')
        ->where('pk <', $param1)
        ->limit(5)
        ->get_compiled_select();

    $highs = $this->db
        ->select('pk, address')
        ->from('unit2')
        ->where('pk >', $param2)
        ->limit(5)
        ->get_compiled_select();

    return $this->db  // don't need select() if you want every column
        ->from("($lows) UNION ($highs)")
        ->order_by(2, 'DESC')  // order by address DESC
        ->get()
        ->result();  // return payload as an array of objects
}

I printed out $this->db->last_query() and added some tabbing to reveal this rendered SQL (quoting characters may vary based on your db driver/dialect):

SELECT *
FROM (
    SELECT "pk", "address"
    FROM "unit1"
    WHERE "pk" < 10000
    LIMIT 5
) UNION (
    SELECT "pk", "address"
    FROM "stl_unit"
    WHERE "stl_unit_pk" > 15000
    LIMIT 5
)
ORDER BY 2 DESC

The result set was exactly as expected -- 10 rows sorted by address column values in descending order.

Because all of the potentially vulnerable parts of this query build are done with active record methods, it is as secure as CodeIgniter allows.


A critical extra note: If you want to append ->where() or ->like() or some other clause to the unionized FROM clause, you'll need to wrap the dual-table expression in outer parentheses and assign a table alias. For example:

return $this->db
    ->from("(($lows) UNION ($highs)) united")
    ->like('address', '1')
    ->order_by(2, 'DESC')
    ->get()
    ->result();
迷离° 2024-08-24 09:09:52

这是我创建的解决方案:

$query1 = $this->db->get('Example_Table1');
$join1 = $this->db->last_query();
$query2 = $this->db->get('Example_Table2');
$join2 = $this->db->last_query();
$union_query = $this->db->query($join1.' UNION '.$join2.' ORDER BY column1,column2);

Here's a solution I created:

$query1 = $this->db->get('Example_Table1');
$join1 = $this->db->last_query();
$query2 = $this->db->get('Example_Table2');
$join2 = $this->db->last_query();
$union_query = $this->db->query($join1.' UNION '.$join2.' ORDER BY column1,column2);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文