Eine zu vielen Link -Tabellen, die doppelte Zeilen zurückgegeben haben
-
18-09-2019 - |
Frage
Alles, was ich bisher gesehen habe, geht darum, doppelte Einträge in einer Datenbank automatisch zu entfernen. Ich möchte zu Beginn betonen, dass dies das ist Es gibt keine doppelten Daten in der Datenbank. Ich werde auch mit der Tatsache beginnen, dass ich immer noch etwas über RDBMS -Design, Normalisierung, Beziehungen und vor allem SQL lerne!
Ich habe eine Client -Tabelle mit einer ClientID (PK) und einem Client_Name. Ich habe eine Rollentabelle mit einem Rollen- (PK) und einem Rollennamen. Jeder Client kann mehrere Rollen zugeordnet haben. Also habe ich eine Client_Role_Link -Tabelle mit ClientID und Rollen -ID als zwei Feldern erstellt. Dann leite ich das:
SELECT client.client_name, role.role_name FROM client
LEFT JOIN client_role_link ON client_role_link.clientid=client.clientid
LEFT JOIN role ON client_role_link.roleid=role.roleid
WHERE (role.roleid='1' OR role.roleid='2')
Nehmen wir also an, ich habe einen Kunden mit zwei Rollen (Rollen '1' und '2'). Diese Abfrage gibt zwei Zeilen zurück, eine für jede Rolle. Wenn ich diese Ergebnisse zurück bekomme, verwende ich a while
Schleife, um die Ergebnisse durchzuführen und sie in a auszugeben <select>
aufführen. Es verursacht dann zwei <option>
's mit demselben Client aufgeführt.
Ich verstehe, warum meine Frage zwei Zeilen zurückgibt, es macht Sinn. Hier kommt also die zweifache Frage:
- Gibt es ein besseres Datenbank-/Tabellendesign, das ich verwenden sollte, oder eine optimiertere Abfrage?
- Oder soll ich das im PHP bewältigen? Wenn ja, gibt es eine elegantere Lösung, die alle Ergebnisse in ein Array hinzufügen, dann durch das Array zurückgehen und Duplikate entfernen?
Gedanken?
Lösung
Wenn Sie beide Rollen zeigen möchten, dann ist Ihre Frage OK
.
MySQL
unterstützt Array -Datentypen nicht, daher sollten Sie ein assoziatives Array auf dem füllen PHP
Seite mit dem Ergebnis mit den doppelten Clientnamen.
Wenn Sie nur Kunden zeigen müssen, die eine der Rollen haben, verwenden Sie diese Abfrage:
SELECT c.*
FROM client c
WHERE c.clientid IN
(
SELECT roleid
FROM client_role_link crl
WHERE crl.roleid IN (1, 2)
)
Dies gibt einen Datensatz pro Kunden zurück, wird jedoch keine Rollen angezeigt.
Der dritte Weg würde die Rollennamen auf der Serverseite implodieren:
SELECT c.*, GROUP_CONCAT(role_name SEPARATOR ';') AS roles
FROM client c
LEFT JOIN
client_role_link crl
ON crl.clientid = c.clientid
AND crl.roleid IN (1, 2)
LEFT JOIN
role r
ON r.roleid = crl.roleid
GROUP BY
c.id
und explodieren Sie sie weiter PHP
Seite, aber stellen Sie sicher, dass die Rollennamen nicht mit dem Separator mischen.
Andere Tipps
Du könntest benutzen mysql_fetch_assoc () um sie wieder in Array -Form zu bringen. Dann könntest du so etwas haben wie Code ungetestet, kann aber funktionieren:
$sql = "SELECT client.id, client.client_name, role.role_name FROM client LEFT JOIN client_role_link ON client_role_link.clientid=client.clientid LEFT JOIN role ON client_role_link.roleid=role.roleid WHERE (role.roleid='1' OR role.roleid='2')";
$result = mysql_query($sql);
$res = array();
while ($row = mysql_fetch_assoc($result)) {
$res[$row['id']]['roles'][] = $row['role_name'];
$res[$row['id']]['client_name'] = $row['client_name']; //you'll be overwriting each iteration probably a better way
}