Php 如何在一行中显示包含其他表数据的汇总表?
我有以下MySQL方案:Php 如何在一行中显示包含其他表数据的汇总表?,php,mysql,sql,database-design,Php,Mysql,Sql,Database Design,我有以下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 我尝试过使用SQLJOIN,但它看起来有多个冗余。所以我不知道如何更好地使用查询 我用PHP解决了这个问题,通过单
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
我尝试过使用SQLJOIN,但它看起来有多个冗余。所以我不知道如何更好地使用查询
我用PHP解决了这个问题,通过单独的查询接收每行的相关数据,但是这个解决方案太慢了。(事实上,我有1000多行)
那么如何查询和显示这些数据呢
我使用以下方法从DB获取信息:
//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>';
//查看文件伪代码
//表头
foreach($result as$method){
回声';
回显“”。$method['method_t']['id'.';
回显'.$method['method_t']['name'].';
回声“”;
foreach($okp方法['okps']为$okp){
回显“- ”.$okp['id']”。
;
//事实上,使用单独的模板从$okp获得更多数据
}
回声“
”;
回声“”;
foreach($tnveds'方法为$tnved){
回音“- ”。$tnved['id']”。
;
}
//事实上,使用单独的模板从$tnveds获得的数据要多得多
回声“
”;
//诸如此类
回声';
}
回声';
也许由于我缺乏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;
}
$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'];
如果((!is_first)&($m_id_last!=$m_id)){
回声';
回显“.$m_id.”;
回显'.$method['name'].';
回声“”;
埃科奥乌街;
回声“
”;
回声';
$o_str=“”;
}
$o_str.='。$method['o_id']. ;
$is_first=false;
}
为什么不使用单个SQL查询,但在使用内部联接时要小心。
因为在okp表中可以有与方法#1相关的行,但在tnved表中没有与方法#1相关的行,反之亦然
注意:在下面的查询和php代码中,我对okp和tnved表使用了名称列而不是注释列
因此,SQL应该是这样的:
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 |
+-----+-----------+--------------+---------------+-----+---------+
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
执行上述查询后,您将获得如下smth:
接下来,使用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'];
);
}
}
下一个渲染$output
数组,其中$output
数组键是方法id
上面的php代码也可以重构。我提供了基本的例子。基本问题是半笛卡尔积。如果“okp”(对于给定的m_id)中有五行,而“tnved”中有六行,那么一个连接操作将把“okp”中的每一行与“tnved”中的每一行匹配,总共三十行。每“okp”行六份,每“tnved”行五份
如果联接涉及三个、四个、五个表,并且每个表都有十几行或更多行。。。由此产生的重复的聚集变得难以处理
有几种方法可以解决这个问题
如果我要对“method”运行一个查询,并在一个循环中处理来自的每一行,一次一个“m_id”
对于“method”中的每一行,我将执行另一个查询,通过将单个查询与UNION all组合,从“okp”、“tnved”等中获取所有行。这将消除行的重复。通过定义适当的索引,例如“…on 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”鉴别器列。我们的代码可以使用此列中的值来确定哪个查询返回了它。在本例中,每个查询都来自一个表,因此我们只需确定值来自哪个表
如果其中一个表要返回的列比其他表多,我们将向其他查询的选择列表中添加“伪”表达式。这使我们能够满足UNION ALL的要求,其中所有被合并的集合必须具有相同的列数和相同的数据类型
这种方法消除了我们用半笛卡尔积得到的大量重复。这种方法需要对我们处理的每个m_id进行“额外”查询,但是如果我们在一个页面上只放置20个m_id,那么只需要运行20个查询
至于这个php。。。执行查询,为每个绑定占位符提供m_id值。获取结果,并将每一行放入相应的(空的)数组中。从“okc”到$okc[]数组的行,从“tnved”到$tnved[]数组的行
看起来该设置适用于当前的“输出”代码
只要处理数量有限的m_id,并且有适当的可用索引,这种方法就可以相当有效。循环中的基本“控制中断”处理。。。按m的顺序处理行。如果当前行用于相同的m(此m_id=以前的m_id),则跳过输出有关新m的信息。当我们有一个新的m时,只输出关于m的信息。这是一种常见的方法。(我没有深入研究答案中提供的php。)+10。