2009-01-10 4 views
67

J'ai deux tables dans ma base de données:PHP & MYSQL: Comment résoudre les noms de colonnes ambiguës dans l'opération JOIN?

NOUVELLES ('id' - l'id de nouvelles, 'utilisateur' - l'ID utilisateur de l'auteur)

UTILISATEURS ('id' - l'ID utilisateur)

Je veux faire un SELECT * FROM news JOIN users ON news.user = user.id, maintenant, quand je reçois les résultats en PHP, il est quelque chose comme:

$row = mysql_fetch_array($result), et obtenir les noms de colonnes par $row['column-name'] ... comment puis-je obtenir les nouvelles et l'ID utilisateur, ayant le même nom de colonne?

MISE À JOUR: Merci à tous pour vos réponses rapides. Les alias semblent la meilleure solution.

Répondre

109

Vous pouvez définir des alias pour les colonnes que vous sélectionnez:

$query = 'SELECT news.id AS newsId, user.id AS userId, [OTHER FIELDS HERE] FROM news JOIN users ON news.user = user.id' 
+1

Cette réponse a fait les réponses à http://stackoverflow.com/questions/9233387/sql-should-i-use-a-join travailler pour moi, merci! – AVProgrammer

+2

Le principal inconvénient de cette approche est que contrairement à 'SELECT *', la requête est étroitement liée à la structure de la table. C'est-à-dire, chaque fois que vous ajoutez/supprimez/renommez des colonnes dans le schéma, vous devez modifier votre requête en conséquence. –

+3

@RonInbar. 'SELECT *' est un cauchemar de maintenance dans les gros systèmes. Vous suggérez que l'ajout d'une colonne est simple et ne nécessite aucune modification de SQL si vous utilisez 'SELECT *', cependant ce n'est pas le cas comme dans le problème d'alias identifié ici. Il peut également donner un impact de performance inutile si le nouveau champ est grand. Il peut également casser les contrôles côté client qui attendent un certain nombre ou des champs. Je peux continuer, mais les avantages de 'SELECT *' disparaissent très rapidement lorsque vous comprenez l'impact que cela a sur la maintenabilité et la performance. –

38

Vous pouvez utiliser les indices numériques ($row[0]) ou mieux, utilisez AS dans MySQL:

SELECT *, user.id AS user_id FROM ...

+12

Notez également que si vous utilisez wildwarcd '*', il doit être le premier dans la clause select. NOT: 'SELECT user_id, * ...' – Anders

+1

Vrai mais vous pouvez toujours faire SELECT user.id AS user_id, user. * FROM ... 'si l'ordre est important. – Cyrille

8

Vous pouvez faire quelque chose comme

SELECT news.id as news_id, user.id as user_id .... 

Et puis $row['news_id'] sera l'ID de nouvelles et $row['user_id'] sera l'ID de l'utilisateur

1

Si vous ne souhaitez pas aliasser, vous pouvez également préfixer les noms de tables.

De cette façon, vous pouvez mieux automatiser la génération de vos requêtes. En outre, il est une meilleure pratique de ne pas utiliser select * (il est évidemment plus lent que simplement sélectionner les champs que vous besoin De plus, seul nom explicitement les champs que vous voulez avoir.

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

Il y a un problème avec ça. PHP va supprimer le préfixe. donc si vous obtenez le résultat, vous ne pouvez pas faire '$ row ['new.id']' .. une solution pour cela? – GameDeveloper

19

Je viens de comprendre ce out. il est probablement une mauvaise pratique, mais cela a fonctionné pour moi dans ce cas.

Je suis l'un des gens paresseux qui ne veulent pas alias ou écrire chaque nom de colonne avec un préfixe de table.

Vous pouvez sélectionner toutes les colonnes d'une table spécifique en utilisant table_name.* dans votre instruction select.

Lorsque vous avez des noms de colonne dupliqués, mysql écrase du premier au dernier. Les données du premier nom de colonne dupliqué seront remplacées quand il rencontrera à nouveau ce nom de colonne. Donc, le nom de la colonne en double qui vient en dernier gagne.

Si je joins 3 tables contenant chacune un nom de colonne dupliqué, l'ordre des tables dans l'instruction select déterminera quelles données je reçois pour la colonne dupliquée.

Exemple:

SELECT table1.* , table2.* , table3.* FROM table1 LEFT JOIN table2 ON table1.dup = table2.dup LEFT JOIN table3 ON table2.dup = table3.dup; 

Dans l'exemple ci-dessus, la valeur de dup je reçois sera de table3.Et si je veux dup être la valeur de table1?

Alors je dois faire ceci:

SELECT table3.* , table2.* , table1.* FROM table1 LEFT JOIN table2 ON table1.dup = table2.dup LEFT JOIN table3 ON table2.dup = table3.dup; 

Maintenant, table1 vient en dernier, donc la valeur de dup sera la valeur de table1.

J'ai obtenu la valeur que je recherchais pour dup sans avoir à écrire chaque colonne et je reçois toujours toutes les colonnes pour travailler. Yay!

Je sais que la valeur de dup doit être la même dans les 3 tables, mais que se passe-t-il si table3 n'a pas de valeur correspondante pour dup? Alors dup serait vide dans le premier exemple, et ce serait un bummer.

+2

S'appuyer sur une commande non documentée qui fonctionne pour vous en ce moment, et ne déclenchera pas d'erreurs si l'implémentation de la base de données change est une idée AWFUL. –

+2

Le piratage de commande est effrayant, mais +1 pour pouvoir sélectionner avec 'table. *' De sorte que je puisse faire 'SELECT table1. *, Table2.this_one_column_need DE table1 INNER JOIN table2 ON ...'. – tobek

2

J'ai eu le même problème avec les tables dynamiques. (Tables supposées avoir un identifiant pour pouvoir se joindre mais sans aucune hypothèse pour le reste des champs.) Dans ce cas, vous ne connaissez pas les alias avant la main.

Dans ce cas, vous pouvez d'abord obtenir les noms de colonnes de table pour toutes les tables dynamiques:

$tblFields = array_keys($zendDbInstance->describeTable($tableName)); 

Où zendDbInstance $ est une instance de Zend_Db ou vous pouvez utiliser l'une des fonctions ici pour ne pas compter sur Zend php pdo: get the columns name of a table

Ensuite, pour toutes les tables dynamiques, vous pouvez obtenir les alias et l'utilisation tableName $ * pour ceux que vous n'avez pas besoin: alias.

$aliases = ""; 
foreach($tblKeys as $field) 
    $aliases .= $tableName . '.' . $field . ' AS ' . $tableName . '_' . $field . ',' ; 
$aliases = trim(',', $aliases); 

Y Vous pouvez envelopper tout ce processus dans une fonction générique et avoir un code plus propre ou devenir plus paresseux si vous le souhaitez :)

8

@Jason. Vous avez raison sauf que php est le coupable et pas mysql. Si vous mettez votre JOIN dans Mysql Workbench, vous obtiendrez trois colonnes avec exactement le même nom (une pour chaque table) mais pas avec les mêmes données (certaines seront null si cette table ne correspond pas à JOIN).

En php si vous utilisez MYSQL_NUM en mysql_fetch_array() alors vous obtiendrez toutes les colonnes. Le problème est lorsque vous utilisez mysql_fetch_array() avec MYSQL_ASSOC. Puis, à l'intérieur de cette fonction, php construit la valeur de retour comme ceci:

$row['dup'] = [value from table1] 

et plus tard ...

$row['dup'] = [value from table2] 

...

$row['dup'] = [value from table3] 

Vous obtiendrez seulement la valeur de table3. Le problème est qu'un ensemble de résultats de mysql peut contenir des colonnes avec le même nom mais les tableaux associatifs dans php n'autorisent pas les clés dupliquées dans les tableaux. Lorsque les données sont enregistrées dans des tableaux associatifs, en php, certaines informations sont silencieusement perdues ...

9

Autre astuce: si vous voulez avoir un code PHP plus propre, vous pouvez créer une vue dans la base de données, par exemple.

Par exemple:

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; 

En PHP:

$sql = "SELECT * FROM view_news"; 
-1

Il existe deux approches:

1. Utilisation d'alias; Dans cette méthode, vous donnez de nouveaux noms uniques (ALIAS) aux différentes colonnes, puis vous les utilisez dans la récupération PHP.

par ex.

SQL $ sql = SELECT student_id FEES_LINK, student_class CLASS_LINK de gauche students_fee_tbl REJOIGNEZ student_class_tbl SUR students_fee_tbl.student_id = student_class_tbl.student_id

PHP $ query = mysql_fetch_assoc ($ sql); // si en utilisant l'ancienne approche

$ query = PDO->fetchAll(); // pas la syntaxe exacte, mais c'est l'approche actuelle

foreach($query as $q){ 
echo $q['FEES_LINK']; 
} 

2.

Utilisation de la position de la place ou de l'index de la colonne resultset; dans ce cas, les positions de tableau sont utilisées pour référencer les noms de colonne dupliqués. Comme ils apparaissent à des positions différentes, les numéros d'index qui seront utilisés sont toujours uniques. Cependant, les numéros de positionnement d'index commencent à 0.

par ex.

$ sql = SELECT student_id, student_class de gauche students_fee_tbl REJOIGNEZ student_class_tbl SUR students_fee_tbl.student_id = student_class_tbl.student_id

PHP

$ query = mysql_fetch_assoc ($ sql); // si vous utilisez l'ancien approche

$ query = PDO-> fetchAll(); // pas la syntaxe exacte mais l'approche actuelle

foreach($query as $q){ 

    echo $q[0]; 

} 

les deux œuvres.

Espérons que ça aide. :)

Questions connexes