2015-12-10 2 views
3

У меня есть некоторые иерархические данные, создали его таким образом:Возвращает массив, содержащий массив массивов объектов

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, так что у меня есть три вложенные для петель, каждые из которых выдающего SELECT заявления (ОБУЧАЕМОГО недоступен, так как он находится дом & я нахожусь в офисе , но я уверен, что вы можете визуализировать его, это достаточно просто).

У меня возникли проблемы с клиентской стороной, пытаясь добавить новую пустую запись и it was suggested, что я должен удалить массив объектов, as shown here.

Однако, что показано только на уровне глубины, поэтому для построения возвращаемого значения было достаточно одного SELECT с while ($row = $stmt->fetch(PDO::FETCH_OBJ)).

Как построить мое возвращаемое значение, которое будет вложенным массивом массива массивов объектов?


[Обновить] Я удалил предыдущую ссылку на скрипку, так как это смутило хотя бы одного человека.

Я хочу, чтобы вернуть массив отделов, каждый из которых содержит данные для этого отдела, а также массив заданий, каждый из которых содержит данные для этой работы, а также массив людей, которые выполняют эту работу


[ Обновление] Вот для вас 50 очков.

Ответы ЙельдарКурмангалиева на 90% завершены, но мне просто нужно некоторое просветление на две небольшие точки.

  • его SQL не показывает данные, связанные с departments. Я подозреваю, что мне просто нужно (INNER?) JOIN departments.*. Но какая именно команда SQL?

  • Что такое код PHP? Я подозреваю, $result = $sqlQuery->fetchAll(PDO::FETCH_ASSOC); или аналогичного

Btw, есть a fiddle для SQL

Моих лучшие усилия возвращать только плоский массив, а не вложенное дерево как отправленный ответ показывает :-(


[Обновить] Спасибо за отличный ответ. Чтобы помочь другим, я опубликовал рабочую скрипку по адресу http://phpfiddle.org/main/code/xfdj-wthc

Обратите внимание, что solutio n поддерживает несколько внешних ключей, где у меня есть только один. Я мог бы упростить код для личного использования, но спасибо @trincot за то, что он настолько гибкий, что может быть полезным для других.

+2

Я не могу понять, что проблема здесь. Если вам нужно вернуть полные данные, это возможно, выбрав отделы, чем для каждого отдела, выбирающего задания, и для каждой работы, выбрав людей. После этого вы json_encode и возвращаетесь как строка к функции JavaScript Ajax. – DDeme

+0

Whooops !! просто 'SELECT * FROM department'? Знаете ли вы, это звучит правильно! Извините, здесь 7 утра, и у меня было 2,5 часа езды. Я все еще должен спать. Не стесняйтесь публиковать это как ответ, в свете моего обновления вопроса. – Mawg

+1

@DDeme, это сработает, но с большими наборами данных это приведет к множеству выполнений запросов (для каждого задания в каждом отделе вы выполнили бы запрос для извлечения peeps). Я думаю, что более эффективно получать все данные с одним запросом, а затем строить из них структуру вывода. – trincot

ответ

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) и т.д.

+0

Thais выглядит великолепно! Однако, можно ли это сделать общим? Очевидно, есть внешние ключи (department_id и job_id), но я хотел бы иметь возможность добавлять больше столбцов в таблицы без обновления кода. Кроме того, мне любопытно, почему вам нужны петли, а @ Yeldar этого не сделал. просто хочу, чтобы он работал. – Mawg

+1

Я полностью обновил свой ответ, теперь с более общим решением. Я не видел никакого кода PHP из Yeldar, поэтому я не уверен, что мы можем сказать, что он мог бы сделать это без циклов. – trincot

+0

Спасибо ** ОЧЕНЬ ** много. опубликовал рабочую скрипту по адресу http://phpfiddle.org/main/code/xfdj-wthc – Mawg

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. 
    ] 
} 
+0

Примите мои извинения. Эта скрипка вводила в заблуждение. Я только хотел показать данные и забыл о SELECT там, что не имеет отношения к этому вопросу. Мой плохой :-( – Mawg

+1

@Mawg Я обновил свой ответ –

+0

И я возвращаю это моему клиенту как? Я использую 'while ($ row = $ stmt-> fetch (PDO :: FETCH_OBJ))'? – Mawg

Смежные вопросы