更有效的方式来连接表但产生嵌套的结果?

时间:2012-08-02 19:25:11

标签: php mysql codeigniter

使用codeigniter活动记录在PHP中实现这样的结果集的最有效方法是什么?

[2] => stdClass Object
    (
        [id] => 12
        [title] => 2 sections
        [layout_id] => 1
        [layout] => stdClass Object
            (
                [id] => 1
                [file] => 3_column.php
                [title] => 3 Column
            )

        [sections] => Array
            (
                [0] => stdClass Object
                    (
                        [module_id] => 12
                        [section_id] => 1
                    )

                [1] => stdClass Object
                    (
                        [module_id] => 12
                        [section_id] => 2
                    )

            )

    )   

这可以为我提供所需的嵌套结果,但我发现这种方法效率低下(忽略每个查询的select *

public function all()
{
  $rows = $this->db->get('modules')->result();

  foreach($rows as &$row)
  {
    $row->layout = $this->db->get_where('layouts', array('id' => $row->layout_id), 1)->first_row();
    $row->sections = $this->db->get_where('modules_sections', array('module_id' => $row->id))->result();
  }

  return $rows;
}

2 个答案:

答案 0 :(得分:1)

您可以使用一些连接和GROUP_BY子句轻松地将这些查询转换为一个查询。这种方法的最大缺点是它需要对数据进行分组和分隔,但PHP擅长于"爆炸"分隔数据。试试这个:

function all()
{

    $this->db->select("`modules`.*, CONCAT(`layouts`.`id`,'".DATA_SUBDELIMITER."',`layouts`.`title`,'".DATA_SUBDELIMITER."',`layouts`.`file`) AS layout, CAST(GROUP_CONCAT(`sections`.`id`,'".DATA_SUBDELIMITER."',`sections`.`title` SEPARATOR '".DATA_DELIMITER."') AS CHAR) AS sections", false);
    $this->db->from('modules');
    $this->db->join('layouts', 'layouts.id = modules.layout_id');
    $this->db->join('modules_sections', 'modules_sections.module_id = modules.id');
    $this->db->join('sections', 'sections.id = modules_sections.section_id');
    $this->db->group_by('modules.id');

    $rows = $this->db->get()->result_array();
    foreach($rows as &$row)
    {
        foreach($row as $k=>&$r)
        {
            if($k=='layout' || $k=='sections')
            {
                $new_r = explode(DATA_DELIMITER, $r);
                foreach($new_r as &$c)
                {
                    $e = explode(DATA_SUBDELIMITER,$c);
                    $c = array();
                    list($c['id'],$c['title']) = $e;
                    if(!empty($e[2])) $c['file'] = $e[2];
                }
                if($k=='layout') $new_r = $new_r[0];
                $r = $new_r;
            }
        }
    }

    return $rows;
}

此示例使用DATA_DELIMITER和DATA_SUBDELIMITER作为将分隔数据的字符。如果您使用这些常量,那么您应该在application / config / constants.php文件中定义它们。也许是这样的:

define('DATA_DELIMITER','||');
define('DATA_SUBDELIMITER','##');

测试此代码以产生如下结果:

Array
(
    [0] => Array
        (
            [id] => 1
            [title] => Module 1
            [layout_id] => 1
            [layout] => Array
                (
                    [title] => 3 Column
                    [id] => 1
                    [file] => 3_column.php
                )

            [sections] => Array
                (
                    [0] => Array
                        (
                            [title] => Section 1
                            [id] => 1
                        )

                    [1] => Array
                        (
                            [title] => Section 2
                            [id] => 2
                        )

                )

        )

    [1] => Array
        (
            [id] => 2
            [title] => Module 2
            [layout_id] => 2
            [layout] => Array
                (
                    [title] => 2 Column
                    [id] => 2
                    [file] => 2_column.php
                )

            [sections] => Array
                (
                    [0] => Array
                        (
                            [title] => Section 1
                            [id] => 1
                        )

                    [1] => Array
                        (
                            [title] => Section 3
                            [id] => 3
                        )

                )

        )

    [2] => Array
        (
            [id] => 3
            [title] => Module 3
            [layout_id] => 1
            [layout] => Array
                (
                    [title] => 3 Column
                    [id] => 1
                    [file] => 3_column.php
                )

            [sections] => Array
                (
                    [0] => Array
                        (
                            [title] => Section 3
                            [id] => 3
                        )

                )

        )

    [3] => Array
        (
            [id] => 4
            [title] => Module 4
            [layout_id] => 2
            [layout] => Array
                (
                    [title] => 2 Column
                    [id] => 2
                    [file] => 2_column.php
                )

            [sections] => Array
                (
                    [0] => Array
                        (
                            [title] => Section 1
                            [id] => 1
                        )

                    [1] => Array
                        (
                            [title] => Section 2
                            [id] => 2
                        )

                    [2] => Array
                        (
                            [title] => Section 3
                            [id] => 3
                        )

                    [3] => Array
                        (
                            [title] => Section 4
                            [id] => 4
                        )

                )

        )

)

答案 1 :(得分:0)

效率在这里是一种相对术语。

如果您正在寻找最小化sql server上的查询,您可以始终序列化您的对象并将它们存储在缓存表中,那么您只需要一次查找,但您必须在任何类型的上保持这些对象写操作。除此之外,您可能只需要加载测试并查看瓶颈的位置。有时,多个查询可能比巨大的多表连接更快。