2015-11-02 2 views
3

У меня есть 4 таблицы в базе данных, которые позволяют мне управлять своего рода «контрольным списком». В нескольких словах для каждого pathology у меня есть большой шаг (process), разбитый на несколько из tasks. Все это связано с конкретной операцией (progress.case_id) в сводной таблице.MySQL лучший способ запросить базу данных для отображения контрольного списка

database.pathology 
+--------------+------------+ 
| id_pathology | name | 
+--------------+------------+ 
|   1 | Pathology1 | 
|   2 | Pathology2 | 
|   3 | Pathology3 | 
+--------------+------------+ 

database.process 
+------------+----------+--------------+----------------+ 
| id_process | name | pathology_id | days_allocated | 
+------------+----------+--------------+----------------+ 
| 1   | BigTask1 | 2   | 5    | 
| 2   | BigTask2 | 2   | 3    | 
| 3   | BigTask3 | 2   | 6    | 
| ...  | ...  | ...   | ...   | 
+------------+----------+--------------+----------------+ 

database.task 
+---------+-------+------------+ 
| id_task | name | process_id | 
+---------+-------+------------+ 
| 1  | Task1 | 1   | 
| 2  | Task2 | 1   | 
| 3  | Task3 | 1   | 
| 4  | Task4 | 2   | 
| ...  | ... | ...  | 
+---------+-------+------------+ 

database.progress 
+-------------+---------+---------+---------+------------+---------+ 
| id_progress | task_id | case_id | user_id | date | current | 
+-------------+---------+---------+---------+------------+---------+ 
|   1 |  1 |  120 |  2 | 2015-11-02 |  1 | 
|   2 |  2 |  120 |  2 | 2015-11-02 |  0 | 
|   3 |  1 |  121 |  3 | 2015-11-02 |  1 | 
+-------------+---------+---------+---------+------------+---------+ 

Я должен показать что-то вроде этого

enter image description here

Мой вопрос: что является наиболее эффективным способом, чтобы продолжить?

Является ли быстрее запрашивать только одну таблицу (прогресс), чтобы отображать наиболее и только затем запрашивать другую, чтобы получить имена разного процесса и дней?

Возможно, совместная функция более эффективна?

Или вы считаете, что моя структура базы данных более не подходит?

Для каждого случая мы можем иметь aproximaly 50 задач, с текущим полем, переведенным в флажок. Также запущен фоновый скрипт. Он анализирует дни, предоставленные на основе оставшихся дней, чтобы определить, может ли быть задержка для данного конкретного случая.

Для каждого случая таблица прогресса уже заполнена всей задачей, связанной с патологией корпуса. И текущее поле всегда «0» в начале.

Я уже пробовал несколько вещей, как

$result = $db->prepare("SELECT DISTINCT process_id,process.name FROM task, progress,process WHERE progress.task_id = task.id_task AND task.process_id = process.id_process AND progress.case_id = ?");  
$result->execute(array($id)); 
foreach($result as $row) 
{ 
    echo "<b>".$row[1]."</b><br>"; 
    $result = $db->prepare("SELECT name,id_task FROM task WHERE process_id = ?");  
    $result->execute(array($row[0])); 
    foreach($result as $row) 
    { 
     echo $row[0]; 
     $result = $db->prepare("SELECT user_id, date, current FROM progress WHERE progress.task_id = ? AND case_id = ?");  
     $result->execute(array($row[1], $id)); 
     foreach($result as $row) 
     { 
     if($row[2] == 0) 
     {echo "<input type='checkbox' />";} 
     else 
     { 
      echo "<input type='checkbox' checked/>"; 
      echo "user : ".$row[0]." date : ".$row[1]."<br>"; 
     }    
     }   
    } 

Но я уверен, что я не делаю это правильно. Должен ли я изменить инфраструктуру базы данных? Должен ли я использовать определенный трюк MySQL? Или, может быть, только более эффективная обработка PHP?

+3

Вложенных запросов, где внутренние запросы используются данные из внешнего запросы почти всегда могут быть лучше написаны как один запрос на объединение. –

+0

Чтобы добавить к комментариям @MarcB, вы должны распознавать вложенные запросы как анти-шаблон разработки программного обеспечения. Вы все время пытаетесь найти альтернативный способ решить проблему, когда увидите этот анти-шаблон. Это не значит, что всегда будет лучший подход, но, как уже отмечалось, вы почти всегда найдете, что это так. –

+0

В MySQL рассмотрим тип данных 'SET'. –

ответ

3

С точки зрения эффективности запрос базы данных является одной из самых медленных операций, которые вы можете выполнять. Все, что вы можете сделать, чтобы уменьшить количество запросов, которые вы создадите, будет иметь большое значение для ускорения работы вашего приложения.

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

Быстро лучше, чем медленно.

Медленно лучше, чем сломан.

К вашей конкретной проблеме, если возможно, никогда не требуется запрос внутри цикла. Особенно, когда этот цикл управляется данными, которые вы извлекаете из той же базы данных. Это запах кода, который требует правильного использования JOIN s.

Поиск в Google Image для SQL Join Diagrams показывает множество примеров диаграмм Венна, которые показывают разные типы данных, возвращаемых с каждым JOIN. Когда вы сомневаетесь, вы обычно хотите LEFT JOIN s.

Итак, давайте определить ваши отношения:

  • Патология

    • Неиспользованные в результатах.
    • Найдите способ включить его в свой запрос, так как в вашем макете появляется «Pathology2».
  • Процесс

    • Список литературы Патология в отношении один-ко-многим. Каждый процесс может иметь одну патологию, но каждая патология может иметь 0 или более процессов.
  • Задача

    • Ссылки Задача в отношении один-ко-многим. Задача содержит дочерние элементы процесса.
  • Прогресс

    • Список литературы Задача, а также не показаны Case и пользователем. Прогресс, как представляется, представляет собой детали задачи при ссылке на конкретный случай и пользователя.
    • Я предполагаю, что существует бизнес-ограничение, где task_id, case_id и user_id должны быть уникальными ... То есть пользователь 1 может иметь только 1 запись прогресса для задачи 1 и случая 100.
    • Кроме того, для задачи, также выступает в качестве моста между Task, Case и User, предоставляя отношения «многие ко многим» к трем таблицам. Поскольку Task является прямым потомком процесса, а Process является прямым ребенком Pathology, он дает отношение «многие ко многим» к патологии.
  • Case

    • Inferred существование этой таблицы.
    • Ссылка на задание.
  • Пользователь

    • Inferred существование этой таблицы.
    • Ссылка на задание.

На основании этой таблицы структуры, наши основные группы будет случай, Патология, и пользователя.

То есть, если вы вошли в систему пользователя, и вы хотите посмотреть на ваш прогресс по делу, вы хотели бы видеть следующее:

Case 110: 
    Pathology1: 
     BigTask1: 
      Task1: X 
      Task2: [] 
     BigTask2: 
      Task3: X 
    Pathology2: 
     BigTask3: 
      Task4: [] 
Case 120: 
    Pathology1: 
     BigTask1: 
      Task1: [] 

Мы хотели бы ID пользователя == 1; Наша первая сортировка будет основываться на случай Наша вторая сортировка будет основываться на Патологии Наша третья сортировка будет основываться на процессе И наша последняя сортировка будет по Задаче ...

Таким образом, данные, чтобы получить наш Вышеприведенные результаты будут: «ORDER BY»

+------+------------+----------+-------+----------+ 
| case | pathology | process | task | progress | 
+------+------------+----------+-------+----------+ 
| 110 | Pathology1 | BigTask1 | Task1 | 1  | 
| 110 | Pathology1 | BigTask1 | Task2 | 0  | 
| 110 | Pathology1 | BigTask2 | Task3 | 1  | 
| 110 | Pathology2 | BigTask3 | Task4 | 0  | 
| 120 | Pathology1 | BigTask1 | Task1 | 0  | 
+------+------------+----------+-------+----------+ 

Наша п от последнего до первого ... ORDER BY task, process, pathology, case ... мы могли бы уладить это в PHP, но база данных лучше, чем мы. Если ваши индексы настроены правильно, базе данных, возможно, даже не придется сортировать вещи, она просто будет их извлекать по порядку.

Запрос получить вышеуказанные данные для конкретного пользователя является:

SELECT 
    prog.case_id AS case, 
    path.name AS pathology, 
    proc.name AS process, 
    task.name AS task, 
    prog.current AS progress 
FROM 
    pathology path 
LEFT JOIN process proc ON path.id_pathology = proc.pathology_id 
LEFT JOIN task ON task.process_id = proc.id_process 
LEFT JOIN progress prog ON task.id_task = prog.task_id 
WHERE prog.user_id = :userid 
ORDER BY task, process, pathology, case 

Вашего PHP может затем быть вдоль линий

<?php 

$sql = <<<EOSQL 
SELECT 
    prog.case_id AS case, 
    path.name AS pathology, 
    proc.name AS process, 
    task.name AS task, 
    prog.current AS progress 
FROM 
    pathology path 
LEFT JOIN process proc ON path.id_pathology = proc.pathology_id 
LEFT JOIN task ON task.process_id = proc.id_process 
LEFT JOIN progress prog ON task.id_task = prog.task_id 
WHERE prog.user_id = :userid 
ORDER BY task, process, pathology, case 
EOSQL; 

$result = $db->prepare($sql);  
$result->execute(array(':userid' => $id)); 
$rows = $result->fetchAll(PDO::FETCH_ASSOC); 

foreach ($rows as $row) { 
    var_dump($row); 
    // array(5) { 
    //  ["case"]=> 
    //  int(110) 
    //  ["pathology"]=> 
    //  string(10) "Pathology1" 
    //  ["process"]=> 
    //  string(8) "BigTask1" 
    //  ["task"]=> 
    //  string(5) "Task1" 
    //  ["progress"]=> 
    //  int(1) 
    // } 
} 
+0

Казалось бы, ваш порядковый номер 'ORDER BY' должен быть отменен из того, что вы показали, если вы хотите напрямую отображать результаты из набора результатов, не помещая результаты в какую-то промежуточную структуру данных, которая позволяла бы группировать в каждом случае на верхний уровень. –

+0

@MikeBrant Возможно, я не запускал это напрямую, и прошло некоторое время с тех пор, как мне пришлось написать предложение ORDER BY. Я понимаю, что БД сначала сортируется по задаче, затем по процессу, затем по патологии, затем по отдельности, оставляя все в одном и том же случае вместе. Если мое предположение неверно, достаточно просто изменить порядок столбцов. – Ghedipunk

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