如何在连续的表格中显示其他表格数据?

如何在连续的表格中显示其他表格数据?

问题描述:

我有以下MySQL的方案:如何在连续的表格中显示其他表格数据?

Method table: PK id, name, comment 
Okp table: PK id, FK method_id, comment 
Tnved table: PK id, FK method_id, comment 

Okp --many to one--> Method <-- many to one-- Tnved 

图像表示:

Link to image represenation

我需要从方法显示HTML汇总表。但是每个方法(每行)都可以有来自其他表格的许多数据,我需要将它们全部显示出来。

它看起来像这样:

Methods summary 
+-----+-----------+--------------+---------------+-----+---------+ 
| id | name  | All OKP data | All TNVED data| ... | Comment | 
+-----+-----------+--------------+---------------+-----+---------+ 
| 1 | Cloth 1 | 841000  | 5007000000 | ... | Special | 
|  |   | 842000  | 5111000000 |  |   | 
|  |   | 843000  | 5112000000 |  |   | 
|  |   | 844000  | ... much more |  |   | 
|  |   | ...much more |    |  |   | 
+-----+-----------+--------------+---------------+-----+---------+ 
| 2 | Game 76 | 259000  | 6100000000 | ... | Nice | 
|  |   | 816700  | 6200000000 |  |   | 
|  |   | 880000  | 6400000000 |  |   | 
|  |   | ...much more | ...much more |  |   | 
+-----+-----------+--------------+---------------+-----+---------+ 
| ... | ...  | ...   | ...   |  | ...  | 
+-----+-----------+--------------+---------------+-----+---------+ 
| 999 | T-shirt 3 | 831701  | 6302600000 | ... | Bad  | 
+-----+-----------+--------------+---------------+-----+---------+ 

我tryed使用SQL JOIN,但它看起来无情无义具有多重冗余。所以我不知道如何更好地使用查询。

我用PHP解决了这个问题,通过单独的查询接收每行的相关数据,但是这个解决方案太慢了。 (实际上我有1000多行)。

那么如何查询和显示这些数据呢?

我用下面的方法来从数据库获取信息:

//Model-file pseudo-code 
$result = array(); 
$methods = $this->db 
    ->select('*') 
    ->from('method') 
    ->get() 
    ->result(); 
$i = 0; 
foreach ($methods as $method){ 
    $result[$i]['method_t'] = $method; 
    $result[$i]['okps'] = $this->db 
     ->select('*') 
     ->from('okp') 
     ->where('method_id', $method['id]') 
     ->get() 
     ->result(); 
    $result[$i]['tnveds'] = $this->db 
     ->select('*') 
     ->from('tnved') 
     ->where('method_id', $method['id]') 
     ->get() 
     ->result(); 
    //so on 
    $i++; 
} 

我用下面的方法来显示汇总表:

//View-file pseudo-code 
//Table header 
foreach ($result as $method) { 
    echo '<tr>'; 
    echo '<td>' . $method['method_t']['id'] . '</td>'; 
    echo '<td>' . $method['method_t']['name'] . '</td>'; 
    echo '<td><ul>'; 
    foreach ($method['okps'] as $okp) { 
     echo '<li>' . $okp['id'] . '</li>'; 
     //in fact much more data from $okp with separate template 
    } 
    echo '</ul></td>'; 
    echo '<td><ul>'; 
    foreach ($method['tnveds'] as $tnved) { 
     echo '<li>' . $tnved['id'] . '</li>'; 
    } 
    //in fact much more data from $tnveds with separate template 
    echo '</ul></td>'; 
    //so on 
    echo '</tr>'; 
} 
echo '</table>'; 

也许我失去了一些东西,由于我的缺乏PHP技能,但我没有看到为什么你无法一次性获得所有记录,然后只是使用php来显示它的方式。下面是一个例子,但我与它缺乏经验的PHP只能被描述为伪代码:

select 
    m.id as m_id, 
    m.name as m_name, 
    m.comment as m_comment, 
    o.id as o_id, 
    o.comment as o_comment, 
    t.id as t_id, 
    t.comment as t_comment 
from 
    method m 
    inner join okp o 
    on m.id = o.method_id 
    inner join tnved t 
    on m.id = t.method_id 
order by m.id, o.id, t.id; 

的PHP,像下面这样。我省略了tvned的东西,因为您可以通过复制okp部分的模型来添加它。

$is_first=true; 
$m_id_last = 0; 
$m_id = 0; 
$o_id_last = 0; 
$o_id = 0; 
$o_str = ""; 
foreach ($result as $method) { 
    $m_id_last = $m_id; 
    $m_id = $method['m_id']; 
    if ((!is_first) && ($m_id_last != $m_id)) { 
     echo '<tr>'; 
     echo '<td>' . $m_id . '</td>'; 
     echo '<td>' . $method['name'] . '</td>'; 
     echo '<td><ul>'; 

     echo o_str; 

     echo '</ul></td>'; 
     echo '</tr>'; 

     $o_str = ""; 
    } 
    $o_str .= '<li>' . $method['o_id'] . '</li>'; 
    $is_first=false; 
} 
+0

循环中的基本“控制中断”处理...按m的顺序处理行。如果当前行为相同的m(this m_id = previous m_id),则跳过输出有关新m的信息。当我们有一个新的m时,只输出有关m的信息。这是一种常见的方法。 (我还没有深入到答案中提供的php。)+10。 – spencer7593

为什么不使用单个SQL查询,但在使用INNER JOIN时要小心。 因为您可以在okp表中具有方法1相关行,但在表中没有任何方法#1的行,反之亦然。下面我用列,而不是OKPtnved表评论列的查询和PHP代码:

当心

因此,SQL应该是水木清华这样的:

SELECT m.id, o.id AS oid, o.name AS oname, t.id AS tid, t.name as tname, m.comment 
FROM 
(method AS m LEFT JOIN okp AS o ON m.id = o.method_id) 
LEFT JOIN tnved AS t ON m.id = t.method_id 
ORDER BY m.id 

查询执行后上面你就会有水木清华这样的: https://drive.google.com/a/thepaydock.com/file/d/0B3C0Ywfdde5Fa2lPc0FBdlZENG8/view?usp=drivesdk

下一个迭代查询结果与PHP行:

$output = array(); 
foreach($results AS $id => $method) { 

    $output[$id]['okps'] = array(); 
    $output[$id]['tnveds'] = array(); 

    if(!is_null($method['oid'])) { 
     $output[$id]['okps'][$method['oid']] = array(
      'name' => $method['oname']; 
     ); 
    }; 

    if(!is_null($method['tid'])) { 
     $output[$id]['tnveds'][$method['tid']] = array(
      'name' => $method['tname']; 
     ); 
    } 
} 

Next render $output array其中$output array key is method_id

上面的php代码也可以重构。我提供了一个基本的例子。

基本问题是半笛卡尔产品。如果“okp”(对于给定的m_id)有五行,而“tnved”有六行,则连接操作将与来自“okp”的每行匹配来自“tnved”的每行,共有三十行。每个“okp”行的6份副本,每个“tnved”行的5份副本。

如果在连接中涉及三个,四个,五个表格,并且每个表格都有十几个或更多行......那么由此产生的复制集合变得笨拙。


有几种方法可以解决这个问题。

如果我要运行针对“方法”的查询,并从一个循环,一个“M_ID”在同一时间处理每一行...

对于从“方法”的每一行,我会执行另一个查询来从“okp”,“tnved”等中取回所有行。通过将单个查询与UNION ALL相结合。这将消除行的重复。通过适当的索引例如“...在okp(m_id,id)”上,查询应该非常高效。

例如:

SELECT okp.m_id  AS m_id 
     , 'okp'  AS src 
     , okp.id  AS id 
     , okp.comment AS comment 
    FROM okp 
    WHERE okp.m_id = ? 
    ORDER BY okp.m_id, okp.id 

    UNION ALL 

    SELECT tnved.m_id AS m_id 
     , 'tnved'  AS src 
     , tnved.id  AS id 
     , tnved.comment AS comment 
    WHERE tnved.m_id = ? 
    ORDER BY tnved.m_id, tnved.id 

我们使用UNION ALL而不是UNION,所以结果只是连接到一起,并避免排序和去除重复行的开销。

请注意,我们包含一个“src”鉴别器列。我们的代码可以使用此列中的值来确定哪个查询返回了它。在这种情况下,每个查询都来自单个表,因此我们可以识别这些值来自哪个表。

如果其中一个表比其他查询有更多的列要返回,我们将“dummy”表达式添加到其他查询的SELECT列表中。这可以让我们满足UNION ALL的要求,其中所有组合的集合必须具有相同数量的列和相同的数据类型。

这种方法消除了我们用半笛卡尔产品获得的大量重复。这种方法需要对我们处理的每个m_id进行“额外”查询,但是如果我们只在页面上放置20个m_id,则只有20个查询要运行。


只要php为此...执行查询,为每个绑定占位符提供m_id值。获取结果,并将每行放入适当的(清空)数组中。从“okc”到$ okc []数组的行,从“tnved”到$ tnved []数组中的行。

看起来这样的设置可以用于当前的“输出”代码。

只要你处理M_ID的数量有限,而且有可用的合适的索引,这种方法可能是相当有效的。