2015-11-02 60 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

我的问题是:什么是进行最有效的方法是什么?

查询只有一个表(进度)显示最多,然后只查询另一个表以获取不同过程和天的名称是更快?

也许联合功能更有效率?

或者你认为我的数据库结构不是更合适吗?

对于每种情况,我们可以有近似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的评论中,YOu应该将嵌套查询识别为软件开发反模式。当你看到这种反模式时,你总是寻找另一种解决问题的方法。这并不是说总会有更好的方法,但正如所指出的那样,你几乎总是会发现这种情况。 –

+0

在MySQL中,考虑'SET'数据类型。 –

回答

3

就效率而言,数据库查询是您可以执行的最慢操作之一。任何可以减少查询数量的方法都可以大大提高应用程序的速度。

但比这更重要的是,您的应用程序需要按照设计工作,这意味着开发人员需要了解正在发生的事情,数据不应该等待被覆盖,而初级开发人员将任务是在3年内维持这一点不会想把头发撕掉。

速度比慢。

缓慢比破碎好。

对于您的特定问题,如果可能,永远不要在循环中查询。尤其是当该循环由您从同一个数据库提取的数据控制时。这是一种代码异味,需要正确使用JOIN

谷歌图片搜索SQL Join Diagrams显示了很多维恩图的例子,显示了每个JOIN返回的不同类型的数据。如有疑问,您通常需要LEFT JOIN s。

所以,让我们找出你的人际关系:

  • 病理

    • 未使用的结果。
    • 找到一种方法将它合并到您的查询中,因为“Pathology2”出现在您的模型中。
  • 过程

    • 参考病理学在一对多的关系。每个进程可以有一个病理学,但每个病理可以有0个或更多个进程。
  • 任务

    • 引用任务在一个一对多的关系。任务包含Process的子项。
  • 进展

    • 参考任务,以及未示出的外壳和用户。在引用特定案例和用户时,进度似乎是任务的细节。
    • 我假设有一家企业的约束,其中TASK_ID,CASE_ID和USER_ID必须是唯一的......也就是说,用户1只能有任务1和外壳100
    • 1个进展条目除了举办细节对于任务来说,它也充当了任务,案例和用户之间的桥梁,为这三个表提供了多对多的关系。由于Task是Process的直接子级,Process是Pathology的直接子级,因此它与病理学提供了多对多的关系。
  • 案例

    • 此表的推断存在。
    • 引用任务。
  • 用户

    • 此表中的推断的存在。
    • 引用任务。

基于此表的结构,我们的主要团体将区分,病理学,和用户。

也就是说,如果你登录的用户,你想看看凯斯你的进步,你会希望看到以下内容:

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

我们希望用户ID == 1; 我们的第一个排序将基于案例 我们的第二个排序将基于病理 我们的第三个排序将基于流程 而我们最后的排序将是对任务...

因此,数据让我们上述结果将是:

+------+------------+----------+-------+----------+ 
| 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子句是从后到前... 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