Ich habe zwei Tabellen in meiner Datenbank:
NEWS-Tabelle mit Spalten:
id
- die Nachrichten-IDuser
- die Benutzer-ID des Autors)
USERS-Tabelle mit Spalten:
id
- die Benutzer-ID
Ich möchte diese SQL ausführen:
SELECT * FROM news JOIN users ON news.user = user.id
Wenn ich die Ergebnisse in PHP erhalte, möchte ich ein assoziatives Array und Spaltennamen von erhalten $row['column-name']
. Wie erhalte ich die Nachrichten-ID und die Benutzer-ID mit demselben Spaltennamen?
php
sql
mysql
mysql-error-1052
Dan Burzo
quelle
quelle
SELECT *
die Abfrage im Gegensatz dazu eng an die Tabellenstruktur gekoppelt ist. Das heißt, wenn Sie Spalten im Schema hinzufügen / löschen / umbenennen, müssen Sie Ihre Abfrage entsprechend ändern.SELECT *
ist ein Wartungsalptraum in großen Systemen. Sie schlagen vor, dass das Hinzufügen einer Spalte einfach ist und bei Verwendung keine Änderung an SQL erfordert.SELECT *
Dies ist jedoch nicht der Fall, wie bei dem hier identifizierten Aliasing-Problem. Es kann auch unnötige Auswirkungen auf die Leistung haben, wenn das neue Feld groß ist. Es kann auch clientseitige Steuerelemente beschädigen, die eine bestimmte Anzahl oder Felder erwarten. Ich kann weitermachen, aber die VorteileSELECT *
verschwinden sehr schnell, wenn Sie die Auswirkungen verstehen, die sie auf die Wartbarkeit und Leistung haben.select table.id
sollte, bei der die Spalte zurückgegeben werden solltetable.id
. Scheint eine einfache Funktion zu sein, die Aliasing verhindern würde. In PHP wird es ein bisschen mühsam sein, die select-Anweisung zu aliasen.Sie können entweder die numerischen Indizes (
$row[0]
) verwenden oder besserAS
in MySQL verwenden:SELECT *, user.id AS user_id FROM ...
quelle
*
, es das erste in der select-Klausel sein muss. NICHT:SELECT user_id,* ...
SELECT user.id AS user_id, user.* FROM ...
wenn die Reihenfolge wichtig ist.Ich habe das gerade herausgefunden. Es ist wahrscheinlich eine schlechte Praxis, aber in diesem Fall hat es bei mir funktioniert.
Ich bin einer der faulen Leute, die nicht jeden Spaltennamen mit einem Tabellenpräfix aliasen oder ausschreiben wollen.
Sie können alle Spalten aus einer bestimmten Tabelle
table_name.*
auswählen, indem Sie sie in Ihrer select-Anweisung verwenden.Wenn Sie Spaltennamen dupliziert haben, wird MySQL vom ersten bis zum letzten überschrieben. Die Daten aus dem ersten duplizierten Spaltennamen werden überschrieben, wenn dieser Spaltenname erneut gefunden wird. Der doppelte Spaltenname, der zuletzt eingeht, gewinnt also.
Wenn ich 3 Tabellen verbinde, die jeweils einen doppelten Spaltennamen enthalten, bestimmt die Reihenfolge der Tabellen in der select-Anweisung, welche Daten ich für die doppelte Spalte erhalte.
Beispiel:
SELECT table1.* , table2.* , table3.* FROM table1 LEFT JOIN table2 ON table1.dup = table2.dup LEFT JOIN table3 ON table2.dup = table3.dup;
Im obigen Beispiel wird der Wert von
dup
I von seintable3
.Was ist, wenn ich
dup
der Wert von sein möchtetable1
?Dann muss ich das machen:
SELECT table3.* , table2.* , table1.* FROM table1 LEFT JOIN table2 ON table1.dup = table2.dup LEFT JOIN table3 ON table2.dup = table3.dup;
Jetzt
table1
kommt der letzte, also ist der Wert vondup
der Wert aus Tabelle1.Ich habe den Wert bekommen, den ich wollte,
dup
ohne jede einzelne verdammte Spalte aufschreiben zu müssen, und ich bekomme immer noch alle Spalten, mit denen ich arbeiten kann. Yay!Ich weiß, dass der Wert von
dup
in allen 3 Tabellen gleich sein sollte, aber was ist, wenntable3
es keinen passenden Wert für gibtdup
? Danndup
wäre im ersten Beispiel leer, und das wäre ein Mist.quelle
table.*
damit ich es tun kannSELECT table1.*, table2.this_one_column_need FROM table1 INNER JOIN table2 ON...
.@ Jason. Sie haben Recht, außer dass PHP der Schuldige ist und nicht MySQL. Wenn Sie Ihre
JOIN
in MySQL Workbench einfügen, erhalten Sie drei Spalten mit genau demselben Namen (eine für jede Tabelle), jedoch nicht mit denselben Daten (einige davon,null
wenn diese Tabelle nicht mit der übereinstimmtJOIN
).Wenn Sie
MYSQL_NUM
in PHP verwenden, erhaltenmysql_fetch_array()
Sie alle Spalten. Das Problem ist, wenn Siemysql_fetch_array()
mit verwendenMYSQL_ASSOC
. Dann baut PHP innerhalb dieser Funktion den Rückgabewert wie folgt auf:$row['dup'] = [value from table1]
und später ...
$row['dup'] = [value from table2]
...
$row['dup'] = [value from table3]
Sie erhalten also nur den Wert aus Tabelle3. Das Problem ist, dass eine Ergebnismenge aus MySQL Spalten mit demselben Namen enthalten kann, assoziative Arrays in PHP jedoch keine doppelten Schlüssel in Arrays zulassen. Wenn die Daten in assoziativen Arrays in PHP gespeichert werden, gehen einige Informationen stillschweigend verloren ...
quelle
Sie können so etwas tun
SELECT news.id as news_id, user.id as user_id ....
Und dann
$row['news_id']
wird die Nachrichten-ID und$row['user_id']
die Benutzer-ID seinquelle
Ein weiterer Tipp: Wenn Sie saubereren PHP-Code wünschen, können Sie eine ANSICHT in der Datenbank erstellen, z
Zum Beispiel:
CREATE VIEW view_news AS SELECT news.id news_id, user.id user_id, user.name user_name, [ OTHER FIELDS ] FROM news, users WHERE news.user_id = user.id;
In PHP:
$sql = "SELECT * FROM view_news";
quelle
Ich hatte das gleiche Problem mit dynamischen Tabellen. (Tabellen, von denen angenommen wird, dass sie eine ID haben, um verbunden werden zu können, jedoch ohne Annahme für den Rest der Felder.) In diesem Fall kennen Sie die Aliase vorher nicht.
In solchen Fällen können Sie zuerst die Tabellenspaltennamen für alle dynamischen Tabellen abrufen:
Wenn $ zendDbInstance eine Instanz von Zend_Db ist oder Sie eine der Funktionen hier verwenden können, um sich nicht auf Zend php pdo zu verlassen: Rufen Sie den Spaltennamen einer Tabelle ab
Dann können Sie für alle dynamischen Tabellen die Aliase abrufen und $ tableName. * Für diejenigen verwenden, für die Sie keine Aliase benötigen:
$aliases = ""; foreach($tblKeys as $field) $aliases .= $tableName . '.' . $field . ' AS ' . $tableName . '_' . $field . ',' ; $aliases = trim($aliases, ',');
Sie können diesen gesamten Prozess in einer generischen Funktion zusammenfassen und einfach saubereren Code haben oder fauler werden, wenn Sie möchten :)
quelle
Wenn Sie keine Lust auf Aliassing haben, können Sie auch einfach die Tabellennamen voranstellen.
Auf diese Weise können Sie die Generierung Ihrer Abfragen besser automatisieren. Es wird auch empfohlen, select * nicht zu verwenden (dies ist offensichtlich langsamer als nur die Auswahl der Felder, die Sie benötigen. Benennen Sie außerdem nur die Felder, die Sie haben möchten, explizit.
SELECT news.id, news.title, news.author, news.posted, users.id, users.name, users.registered FROM news LEFT JOIN users ON news.user = user.id
quelle
$row['new.id']
keine Lösung dafür finden.Hier ist eine Antwort auf das oben Gesagte, die sowohl einfach ist als auch mit zurückgegebenen JSON-Ergebnissen funktioniert. Während die SQL-Abfrage bei Verwendung von SELECT * jeder Instanz identischer Feldnamen automatisch Tabellennamen voranstellt, ignoriert die JSON-Codierung des Ergebnisses zum Zurücksenden an die Webseite die Werte dieser Felder mit einem doppelten Namen und gibt stattdessen einen NULL-Wert zurück .
Genau das, was es tut, ist, die erste Instanz des duplizierten Feldnamens einzuschließen, aber seinen Wert auf NULL zu setzen. Und die zweite Instanz des Feldnamens (in der anderen Tabelle) wird vollständig weggelassen, sowohl der Feldname als auch der Wert. Wenn Sie die Abfrage jedoch direkt in der Datenbank testen (z. B. mit Navicat), werden alle Felder in der Ergebnismenge zurückgegeben. Erst wenn Sie das nächste Mal die JSON-Codierung dieses Ergebnisses durchführen, haben sie NULL-Werte und nachfolgende doppelte Namen werden vollständig weggelassen.
Eine einfache Möglichkeit, dieses Problem zu beheben, besteht darin, zuerst SELECT * auszuführen und anschließend Alias-Felder für die Duplikate zu erstellen. Hier ist ein Beispiel, in dem beide Tabellen Felder mit dem gleichen Namen site_name haben.
SELECT *, w.site_name AS wo_site_name FROM ws_work_orders w JOIN ws_inspections i WHERE w.hma_num NOT IN(SELECT hma_number FROM ws_inspections) ORDER BY CAST(w.hma_num AS UNSIGNED);
Jetzt können Sie im dekodierten JSON das Feld wo_site_name verwenden und es hat einen Wert. In diesem Fall haben Site-Namen Sonderzeichen wie Apostrophe und einfache Anführungszeichen, daher die Codierung beim ursprünglichen Speichern und die Decodierung bei Verwendung des Ergebnisses aus der Datenbank.
...decHTMLifEnc(decodeURIComponent( jsArrInspections[x]["wo_site_name"]))
Sie müssen immer das * zuerst in die SELECT-Anweisung setzen, aber danach können Sie so viele benannte und aliasierte Spalten einfügen, wie Sie möchten, da das wiederholte Auswählen einer Spalte kein Problem verursacht.
quelle
Wenn Sie PDO für eine Datenbankinteraktion verwenden, können Sie den Abrufmodus PDO :: FETCH_NAMED verwenden , um das Problem zu beheben:
$sql = "SELECT * FROM news JOIN users ON news.user = user.id"; $data = $pdo->query($sql)->fetchAll(PDO::FETCH_NAMED); foreach ($data as $row) { echo $row['column-name'][0]; // from the news table echo $row['column-name'][1]; // from the users table echo $row['other-column']; // any unique column name }
quelle
Es gibt zwei Ansätze:
Verwenden von Aliasen; Bei dieser Methode geben Sie den verschiedenen Spalten neue eindeutige Namen (ALIAS) und verwenden sie dann beim PHP-Abruf. z.B
SELECT student_id AS FEES_LINK, student_class AS CLASS_LINK FROM students_fee_tbl LEFT JOIN student_class_tbl ON students_fee_tbl.student_id = student_class_tbl.student_id
und dann die Ergebnisse in PHP abrufen:
$query = $PDO_stmt->fetchAll(); foreach($query as $q) { echo $q['FEES_LINK']; }
Verwenden der Ortsposition oder des Ergebnismengen-Spaltenindex; In diesem Fall werden die Array-Positionen verwendet, um auf die duplizierten Spaltennamen zu verweisen. Da sie an verschiedenen Positionen angezeigt werden, sind die verwendeten Indexnummern immer eindeutig. Die Indexpositionierungsnummern beginnen jedoch bei 0. z
SELECT student_id, student_class FROM students_fee_tbl LEFT JOIN student_class_tbl ON students_fee_tbl.student_id = student_class_tbl.student_id
und dann die Ergebnisse in PHP abrufen:
$query = $PDO_stmt->fetchAll(); foreach($query as $q) { echo $q[0]; }
quelle