返回一组对象数组

时间:2015-12-10 08:20:07

标签: php json

我有一些分层数据,因此创建了它:

CREATE TABLE `departments`
    (`deperatment_id` INTEGER NOT NULL, 
     `department_name` varchar(32) NOT NULL);

  INSERT INTO `departments`(`deperatment_id`, `department_name`)
        VALUES (1, "HR"), (2, "Software"), (3, "Accounts");

CREATE TABLE `jobs` (`deperatment_id` INTEGER NOT NULL,
                   `job_id` INTEGER NOT NULL,
                   `job_name` varchar(32) NOT NULL);

INSERT INTO `jobs` (`deperatment_id`, `job_id`, `job_name`)
         VALUES (1, 1, "Idiot"),
                (1, 2, "Fool"),
                (2, 3, "PHB"),
                (2, 4, "Software guru"),
                (2, 5, "PFY"),
                (3, 6, "Number cruncher");

CREATE TABLE `peeps` (`job_id` INTEGER NOT NULL,
                    `peep_name` varchar(32) NOT NULL);

INSERT INTO `peeps`(`job_id` , `peep_name` )
                 VALUES(1, "Smith"),
                        (2, "Jones Major"),
                        (2, "Jones Minor"),
                        (4, "Mr. In-the-wrong-department"),
                        (4, "Mawg"),
                        (5, "William Topaz McGonagall"),
                        (6, "Blaise Pascal"),
                        (6, "Isaac Newton");

因此,正如您所看到的,可以有一个或多个部门,每个部门可以由一个或多个人完成一个或多个工作。

这是一个整洁的树层次结构,我想返回它以响应一个AJAX请求,所以我有三个嵌套for循环,每个都发出一个SELECT语句(coed不可用,因为它在家里和我我在办公室,但我相信你可以想象它;它很简单。)

我在客户端遇到了一些问题,尝试添加一个新的空白条目,it was suggested我应该停用一组对象as shown here

但是,这仅显示在深度级别上,因此带SELECT的单个while ($row = $stmt->fetch(PDO::FETCH_OBJ))足以构建返回值 - 对象数组。

如何构建我的返回值,它将是一个对象数组数组的嵌套数组?

[更新]我删除了之前对小提琴的引用,因为它至少混淆了一个人。

我想返回一系列部门,每个部门包含该部门的数据,以及一系列工作,每个工作包含该工作的数据,以及执行该工作的一系列人员

[更新]这是一个容易50分的人。

@YeldarKurmangaliyev的答案完成了90%,但我只需要对两个小点进行一些启示。

  • 他的SQL没有显示与departments相关联的数据。我怀疑我只需要(INNER?) JOIN departments.*。但确切的SQL命令是什么?

  • 什么是PHP代码?我怀疑$result = $sqlQuery->fetchAll(PDO::FETCH_ASSOC);或类似的

顺便说一句,SQL

a fiddle

我最好的努力只返回一个平面数组,而不是一个嵌套的树,如发布的答案所示: - (

[更新]感谢您的回答。为了帮助他人,我在http://phpfiddle.org/main/code/xfdj-wthc

发布了一个工作小提琴

请注意,该解决方案支持多个外键,其中我只有一个。我可以简化代码供个人使用,但是感谢@trincot使它变得如此灵活,因为这可能对其他人有用。

2 个答案:

答案 0 :(得分:2)

如果要输出树结构,则不需要使用循环。您只需进行以下查询:

SELECT p.`peep_name`, j.* FROM `peeps` p INNER JOIN `jobs` j ON j.job_id = p.job_id

将返回如下结构:

peep_name                   deperatment_id  job_id  job_name
Smith                           1             1       Idiot
Jones Major                     1             2       Fool
Jones Minor                     1             2       Fool
Mr. In-the-wrong-department     2             4       Software guru
Mawg                            2             4       Software guru
William Topaz McGonagall        2             5       PFY
Blaise Pascal                   3             6       Number cruncher
Isaac Newton                    3             6       Number cruncher

然后,您将能够以此格式输出此数据,或将此数据组合成所需格式的树结构。例如,您可以使用以下格式输出它:

{
    "departments": 
    [
        {
            "ID": 1,
            "jobs": 
            [ 
                { 
                    "ID": 1,
                    "Name": "Idiot"
                    "Peeps": 
                    [
                        "Smith"
                    ]
                },
                {
                    "ID": 2,
                    "Name": "Fool"
                    "Peeps": 
                    [
                        "Jones Major",
                        "Jones Minor"
                    ]
                }
            ]
        },
        // etc.
    ]
}

答案 1 :(得分:1)

以下是一些代码,它们从单独的数组中的每个表中检索数据,然后从中构建最终的数据结构。

这是非常通用的,因为您只需为每对表指定哪些字段是公共密钥(主键和外键,假定它们具有相同的名称):

function loadTable($dbh, $table) {
    // Perform simple table select, and return result set
    $sth = $dbh->prepare("SELECT * FROM $table");
    $sth->execute();
    $rows = $sth->fetchAll(PDO::FETCH_ASSOC);
    return $rows;
}

function connectChildren($parents, $children, $name, $common_keys) {
    /* Returns $parents array, but with each element extended with
     * a $name key, which is an array of matching $children elements.
     * The match is made by comparing the values for each of the $common_keys 
     * in both arrays.
     * When a $children element is added to the $name array, its $common_keys
     * are removed from it as they are already known in the $parents element.
     * (this removal behaviour is optional and could be left out)
     */ 
    $index = [];
    // Build a temporary index to associate $parents elements by their 
    // primary key value (can be composite) 
    foreach ($parents as $i => $parent) {
        $primary_key = [];
        foreach ($common_keys as $common_key) {
            $primary_key[] = $parent[$common_key];
        }
        $index[implode("|", $primary_key)] = $i;
        $parents[$i][$name] = [];
    }
    // Main algorithm: inject $children into $parents
    foreach($children as $child) {
        $foreign_key = [];
        // Collect foreign key value
        foreach ($common_keys as $common_key) {
            $foreign_key[] = $child[$common_key];
            // Remove foreign key from child
            unset($child[$common_key]);
        }
        // Find the corresponding $parents element via the index
        $i = $index[implode("|", $foreign_key)];
        $parents[$i][$name][] = $child;
    }
    return $parents;
}

// Step 1: load all the table data    
$rows_dep = loadTable($dbh, "departments");
$rows_job = loadTable($dbh, "jobs");
$rows_peep = loadTable($dbh, "peeps");


// Step 2: connect the data, layer by layer, in bottom-up order:    
$rows_job = connectChildren($rows_job, $rows_peep,
                            "peeps", ["deperatment_id", "job_id"]);
$rows_dep = connectChildren($rows_dep, $rows_job,
                            "jobs", ["deperatment_id"]);

print_r ($rows_dep);

测试数据的输出:

Array
(
  [0] => Array
    (
      [deperatment_id] => 1
      [department_name] => HR
      [jobs] => Array
        (
          [0] => Array
            (
              [job_id] => 1
              [job_name] => Idiot
              [peeps] => Array
                (
                  [0] => Array
                    (
                      [peep_name] => Smith
                    )
                )
            )
          [1] => Array
            (
              [job_id] => 2
              [job_name] => Fool
              [peeps] => Array
                (
                  [0] => Array
                    (
                      [peep_name] => Jones Major
                    )

                  [1] => Array
                    (
                      [peep_name] => Jones Minor
                    )

                )
            )
        )
    )
  [1] => Array
    (
      [deperatment_id] => 2
      [department_name] => Software
      [jobs] => Array
        (
          [0] => Array
            (
              [job_id] => 4
              [job_name] => Software guru
              [peeps] => Array
                (
                  [0] => Array
                    (
                      [peep_name] => Mr. In-the-wrong-department
                    )

                  [1] => Array
                    (
                      [peep_name] => Mawg
                    )
                )
            )
          [1] => Array
            (
              [job_id] => 5
              [job_name] => PFY
              [peeps] => Array
                (
                  [0] => Array
                    (
                      [peep_name] => William Topaz McGonagall
                    )
                )
            )
        )
    )
  [2] => Array
    (
      [deperatment_id] => 3
      [department_name] => Accounts
      [jobs] => Array
        (
          [0] => Array
            (
              [job_id] => 6
              [job_name] => Number cruncher
              [peeps] => Array
                (
                  [0] => Array
                    (
                      [peep_name] => Blaise Pascal
                    )
                  [1] => Array
                    (
                      [peep_name] => Isaac Newton
                    )
                )
            )
        )
    )
)

然后,您可以继续使用json_encode($departments)