我有以下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
图像表示:
我需要从方法中显示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 |
+-----+-----------+--------------+---------------+-----+---------+
我尝试使用SQL JOIN,但它看起来很怪异,有多个冗余。所以我不知道如何更好地使用查询。
我用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>';
答案 0 :(得分:1)
也许我缺少一些东西,因为我缺乏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;
}
答案 1 :(得分:0)
为什么不使用单个SQL查询,但在使用INNER JOIN
时要小心。
因为您可以在 okp 表中使用方法#1相关的行,但是 tnved 表中的方法#1的任何行都没有,反之亦然。
小心:在查询和php代码中,我使用 name 列代替 comment 列 okp < / em>和 tnved 表。
所以,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'];
);
}
}
接下来渲染$output
数组,其中$output
数组键是 method_id 。
上面的php代码也可以重构。我已经提供了基本的例子。
答案 2 :(得分:0)
基本问题是半笛卡尔产品。如果&#34; okp&#34;有五行(对于给定的m_id)和来自&#34; tnved&#34;的六行,一个连接操作将匹配来自&#34; okp&#34;的每一行。来自&#34; tnved&#34;的每一行,总共三十行。每份六份&#34; okp&#34;行,并且每个&#34; tnved&#34;行。
如果连接中涉及三个,四个,五个表,并且每个表都有十几个或更多行......由此产生的重复集合变得难以处理。
有几种方法可以解决这个问题。
如果我要针对&#34;方法&#34;运行查询,并在循环中处理每一行,则一个&#34; m_id&#34;一次......
对于&#34;方法&#34;中的每一行,我会执行另一个单一查询以从&#34; okp&#34;,&#34; tnved&#34;等获取所有行。通过将各个查询与UNION ALL组合在一起。这将消除行的重复。使用适当的索引定义,例如&#34; ...在okp(m_id,id)&#34;上,查询应该非常有效。
例如:
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,因此结果只是连接在一起,避免了排序和删除重复行的开销。
请注意,我们包含了一个&#34; src&#34;鉴别列。我们的代码可以使用此列中的值来确定返回哪个查询。在这种情况下,每个查询都来自一个表,因此我们可以只识别值来自的表。
如果其中一个表的列数要多于其他表,我们会添加&#34; dummy&#34;表达式到其他查询的SELECT列表。这使我们能够满足UNION ALL的要求,其中所有要组合的集合必须具有相同的列数和相同的数据类型。
这种方法消除了我们使用半笛卡尔产品所带来的大量重复。这种方法需要额外的&#34;查询我们处理的每个m_id,但如果我们只在页面上放置20 m_id,那么它只能运行20个查询。
就此而言php ...执行查询,为每个绑定占位符提供m_id值。获取结果,并将每一行放入适当的(清空)数组中。来自&#34; okc&#34;的行进入$ okc []数组,来自&#34; tnved&#34;进入$ tnved []数组。
看起来该设置适用于当前&#34;输出&#34;代码。
只要您处理有限数量的m_id,并且有适当的索引可用,这种方法可以合理有效。