2016-04-22 4 views
2

Ich habe folgende MySQL Schema:Wie wird die Übersichtstabelle mit anderen Tabellendaten in einer Zeile angezeigt?

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 

Bilddarstellung:

Link to image represenation

Ich bin müssen von Methoden HTML Übersichtstabelle zeigen. Aber jede Methode (jede Zeile) könnte viele Daten aus anderen Tabellen in Feldern haben und ich muss sie alle zeigen.

Es sieht wie folgt aus:

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  | 
+-----+-----------+--------------+---------------+-----+---------+ 

Ich habe versucht SQL zu verwenden JOIN aber es sieht mehrfach redundant monströs. Also ich weiß nicht, wie man Abfragen besser verwendet.

Ich bin es mit PHP gelöst, indem Sie verwandte Daten für jede Zeile mit separaten Abfragen erhalten, aber diese Lösung ist zu langsam. (In der Tat habe ich 1000+ Zeilen).

SO wie Abfragen und Anzeigen solcher Daten?

Ich verwende folgende Methode, um Informationen von der DB zu erhalten:

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

ich folgende Methode Sichtstabelle zeigen:

//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>'; 

Antwort

1

Vielleicht etwas wegen mir fehlt meine Mangel an PHP-Fähigkeiten, aber ich sehe keinen Grund, warum Sie nicht alle Datensätze in einem Schuss bekommen können und dann einfach den PHP verwenden, um es zu zeigen, wie Sie wollen. Hier ist ein Beispiel, aber die PHP kann am besten nur als Pseudo-Code beschrieben werden, wie ich damit wenig Erfahrung haben:

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; 

Für die php, so etwas wie die folgenden. Ich habe das tnned-Zeug weggelassen, da Sie das hinzufügen können, indem Sie einfach das Modell des Okp-Teils kopieren.

$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

Basic "Control Break" Verarbeitung in der Schleife ... Zeilen in der Reihenfolge von m. Wenn die aktuelle Zeile für dasselbe m ist (diese m_id = vorherige m_id), überspringen Sie die Ausgabe von Informationen über ein neues m. Gib nur Informationen über m aus, wenn wir ein neues m haben. Dies ist ein gängiger Ansatz. (Ich habe mich nicht mit dem in der Antwort angegebenen PHP beschäftigt.) +10. – spencer7593

0

Warum nicht eine einzige SQL-Abfrage verwenden, aber vorsichtig sein, wenn Sie INNER JOIN verwenden. Da können Sie für die Methode # 1 verwandte Zeilen in okp Tabelle haben, aber keine Zeilen für Methode # 1 in tnved Tabelle und umgekehrt.

Vorsicht: in Abfrage und PHP-Code unten ich Name Spalte statt Kommentar Spalte für OKP und tnved Tabellen bin mit.

So sollte SQL smth so aussehen:

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 

Nach der Ausführung der Abfrage über Sie smth wie diese haben werden: https://drive.google.com/a/thepaydock.com/file/d/0B3C0Ywfdde5Fa2lPc0FBdlZENG8/view?usp=drivesdk

Weiter Iterierte Abfrageergebnisse Zeilen mit 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']; 
     ); 
    } 
} 

Nächste Render $output Array wo $output Array-Schlüssel ist method_id.

Auch PHP-Code oben kann refaktoriert werden. Ich habe ein einfaches Beispiel angegeben.

0

Das Grundproblem ist das semi-kartesische Produkt. Wenn es fünf Zeilen von "okp" (für gegebene m_id) und sechs Zeilen von "tnved" gibt, wird eine Join-Operation jeder Zeile von "okp" mit jeder Zeile von "tnved" entsprechen, also insgesamt 30 Zeilen. Sechs Kopien jeder "okp" -Reihe und fünf Kopien jeder "tnved" -Reihe.

Wenn drei, vier, fünf Tabellen am Join beteiligt sind und jeder ein Dutzend oder mehr Zeilen hat ... wird das daraus resultierende Konglomerat von Doppelungen unhandlich.


Es gibt mehrere Ansätze, um das Problem zu zähmen.

Wenn ich eine Abfrage für „Methode“ laufen werde, und jede Reihe von in einer Schleife zu verarbeiten, ein „m_id“ zu einer Zeit ...

Für jede Zeile von „Methode“, würde ich Führen Sie eine weitere einzelne Abfrage aus, um alle Zeilen von "okp", "tnved" usw. zurückzubekommen. durch Kombinieren der einzelnen Abfragen mit einer UNION ALL. Dies würde die Duplizierung der Zeilen eliminieren. Mit einem geeigneten Index, der z.B. "... auf okp (m_id, id)" sollten die Abfragen sehr effizient sein.

Zum Beispiel:

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 

Wir verwenden eine UNION ALL und keine UNION, so werden die Ergebnisse nur miteinander verkettet, und vermeiden den Aufwand eine Art und Entfernen von doppelten Zeilen.

Beachten Sie, dass wir eine "src" -Diskriminatorsäule enthalten. Unser Code kann den Wert in dieser Spalte verwenden, um zu bestimmen, welche Abfrage ihn zurückgegeben hat. In diesem Fall stammt jede Abfrage aus einer einzelnen Tabelle, sodass wir einfach die Tabelle identifizieren können, aus der die Werte stammen.

Wenn eine der Tabellen mehr Spalten zurückgibt als die anderen, fügen wir der SELECT-Liste der anderen Abfragen "Dummy" -Ausdrücke hinzu. Damit können wir die Anforderungen von UNION ALL erfüllen, wobei alle zu kombinierenden Sets die gleiche Anzahl von Spalten und dieselben Datentypen haben müssen.

Dieser Ansatz beseitigt eine Menge der Duplizierung, die wir mit einem semi-kartesischen Produkt erhalten. Dieser Ansatz erfordert eine "zusätzliche" Abfrage für jede m_id, die wir verarbeiten, aber wenn wir nur 20 m_id auf einer Seite setzen, müssen nur 20 Abfragen ausgeführt werden.

Soweit die PHP für diese ... führen Sie die Abfrage, Bereitstellung von m_id Wert für jeden der Bindung Platzhalter. Holen Sie die Ergebnisse und jede Zeile in das entsprechende (geleerte) Array. Zeilen von "okc" in ein $ okc [] Array, die Zeilen von "tnved" in ein $ tnved [] Array.

Sieht so aus, als würde diese Einrichtung für den aktuellen "Ausgabe" -Code funktionieren.

Solange Sie eine begrenzte Anzahl von m_id verarbeiten und entsprechende Indizes verfügbar sind, kann dieser Ansatz einigermaßen effizient sein.

Verwandte Themen