2016-04-22 41 views
2

我有以下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>'; 

回答

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; 
} 
+0

循環中的基本「控制中斷」處理...按m的順序處理行。如果當前行爲相同的m(this m_id = previous m_id),則跳過輸出有關新m的信息。當我們有一個新的m時,只輸出有關m的信息。這是一種常見的方法。 (我還沒有深入到答案中提供的php。)+10。 – spencer7593

0

爲什麼不使用單個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代碼也可以重構。我提供了一個基本的例子。

0

基本問題是半笛卡爾產品。如果「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的數量有限,而且有可用的合適的索引,這種方法可能是相當有效的。

相關問題