JeuWeb - Crée ton jeu par navigateur
[PHP] requêtes dûre - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [PHP] requêtes dûre (/showthread.php?tid=3956)

Pages : 1 2


RE: [PHP] requêtes dûre - Plume - 14-11-2010

Z'êtes des artistes les caïds. Vous voyez pas que vous demandez à sélectionner les lignes où l'identifiant du membre vaut 38, que cette valeur est stockée dans la table Batiments_acquis et que donc la ligne que vous voulez afficher n'est pas concernée ? Smile

La clause LEFT marche très bien. Essayez ça pour voir :
SELECT
`batiments_acquis`.`niveaux`,
`liste_batiments`.`id`,
`liste_batiments`.`nom`,
`liste_batiments`.`description`

FROM `liste_batiments`

INNER JOIN `batiments_acquis`
ON `batiments_acquis`.`id_batiments` = `liste_batiments`.`id`

SELECT
`batiments_acquis`.`niveaux`,
`liste_batiments`.`id`,
`liste_batiments`.`nom`,
`liste_batiments`.`description`

FROM `liste_batiments`

LEFT JOIN `batiments_acquis`
ON `batiments_acquis`.`id_batiments` = `liste_batiments`.`id`

La dernière proposition de niahoo va fonctionner. Le seul truc, c'est que sémantiquement il est mieux venu de ne pas mettre ce genre de conditions dans la clause ON d'une jointure mais il y a des exceptions Smile


RE: [PHP] requêtes dûre - niahoo - 14-11-2010

hmm je pige pas, tu postes deux fois la même mais dans aucune des deux n'apparaît «38»

edit: en fait dans ta requete, les bâtiments vont être affichés autant de fois qu'un utilisateur l'a acquis _who, donc oui la clause LEFT marche, mais si on ne sait pas préciser l'ID d'untilisateur tu récup toute la table..


RE: [PHP] requêtes dûre - pascal - 14-11-2010

erf, oui. Dans ce cas, il faut aussi mettre NULL :


SELECT BA.niveaux, LB.id, LB.nom, LB.description
FROM Liste_batiments LB
LEFT JOIN Batiments_acquis BA ON LB.id = BA.id_batiments
WHERE BA.id_membres =38 OR BA.id_membres IS NULL

++

Pascal


RE: [PHP] requêtes dûre - Hell-AstiK - 14-11-2010

(14-11-2010, 01:04 AM)niahoo a écrit : Marrant, le left-join marche pas...

pitetre comme ça ?

SELECT BA.niveaux, LB.id, LB.nom, LB.description
FROM Liste_batiments LB
LEFT JOIN Batiments_acquis BA ON LB.id = BA.id_batiments AND BA.id_membres =38

ceci me donne :
[Image: 4cdfb555ad2b7.jpg]

(14-11-2010, 02:15 AM)_who a écrit : Z'êtes des artistes les caïds. Vous voyez pas que vous demandez à sélectionner les lignes où l'identifiant du membre vaut 38, que cette valeur est stockée dans la table Batiments_acquis et que donc la ligne que vous voulez afficher n'est pas concernée ? Smile

La clause LEFT marche très bien. Essayez ça pour voir :
SELECT
`batiments_acquis`.`niveaux`,
`liste_batiments`.`id`,
`liste_batiments`.`nom`,
`liste_batiments`.`description`

FROM `liste_batiments`

INNER JOIN `batiments_acquis`
ON `batiments_acquis`.`id_batiments` = `liste_batiments`.`id`

SELECT
`batiments_acquis`.`niveaux`,
`liste_batiments`.`id`,
`liste_batiments`.`nom`,
`liste_batiments`.`description`

FROM `liste_batiments`

LEFT JOIN `batiments_acquis`
ON `batiments_acquis`.`id_batiments` = `liste_batiments`.`id`

La dernière proposition de niahoo va fonctionner. Le seul truc, c'est que sémantiquement il est mieux venu de ne pas mettre ce genre de conditions dans la clause ON d'une jointure mais il y a des exceptions Smile
Dans l'ordre :
[Image: 4cdfb58d3e5cd.jpg]
et
[Image: 4cdfb5a08d741.jpg]

Comment tu as fait alors que tu n'a pas sélectionner un membre ? :heuuu:
(14-11-2010, 10:40 AM)pascal a écrit : erf, oui. Dans ce cas, il faut aussi mettre NULL :


SELECT BA.niveaux, LB.id, LB.nom, LB.description
FROM Liste_batiments LB
LEFT JOIN Batiments_acquis BA ON LB.id = BA.id_batiments
WHERE BA.id_membres =38 OR BA.id_membres IS NULL

++

Pascal
Résultat :
[Image: 4cdfb5bdec1e0.jpg]


Merci à tous ! Je doit prendre celle de pascal ou de _who?


RE: [PHP] requêtes dûre - Plume - 14-11-2010

De Pascal. Les deux miennes étaient là pour montrer que la clause LEFT marche forcément Smile


RE: [PHP] requêtes dûre - Hell-AstiK - 14-11-2010

J'ai compris le fonctionnement des jointures, mais après pour les exploiter en PHP, c'est pas trop ca encore...

Si j'ai compris, pour savoir si je met le lien 'Entrer' ou 'Construire', je vérifie si le niveaux est supérieur à 0 ?
si il l'est, je met 'Entrer', si il ne l'est pas(=NULL) je met 'Construire' ??

(en tout cas j'ai fait ca, et ça marche donc bon ^^)

EDIT:
Voilà le code que j'ai actuellement, ça fonctionne bien Cool

$batiments_acquis = $bdd->prepare("SELECT BA.niveaux, LB.id, LB.nom, LB.description
FROM Liste_batiments LB
LEFT JOIN Batiments_acquis BA ON LB.id = BA.id_batiments
WHERE BA.id_membres = :id_user OR BA.id_membres IS NULL");
$batiments_acquis->bindValue(':id_user', $_SESSION['id'], PDO:TongueARAM_INT);
$batiments_acquis->execute();


while($donnees_acquis = $batiments_acquis->fetch()) {
echo $donnees_acquis['nom'].'<br />';
if($donnees_acquis['niveaux'] >= 1) {
echo "<a href='./batiments/".supprimer_accents(lcfirst($donnees_acquis['nom'])).".php'>Entrer</a><br />";
}
else {
echo "<a href='./batiments/construire.php?batiment=".$donnees_acquis['id']."'>Construire</a><br />";
}
echo '<em>'.$donnees_acquis['description'].'</em><br />';
}
Merci les gars (et fille si je ne me suis pas tromper) :bisou:
pardon :good:


RE: [PHP] requêtes dûre - srm - 14-11-2010

Je ne vois pas en quoi sémantiquement la requête de niahoo n'est pas correcte...


RE: [PHP] requêtes dûre - Plume - 14-11-2010

Citation :The conditional_expr used with ON is any conditional expression of the form that can be used in a WHERE clause. Generally, you should use the ON clause for conditions that specify how to join tables, and the WHERE clause to restrict which rows you want in the result set.

Citation :If there is no matching row for the right table in the ON or USING part in a LEFT JOIN, a row with all columns set to NULL is used for the right table. You can use this fact to find rows in a table that have no counterpart in another table:

SELECT left_tbl.*
FROM left_tbl LEFT JOIN right_tbl ON left_tbl.id = right_tbl.id
WHERE right_tbl.id IS NULL;

This example finds all rows in left_tbl with an id value that is not present in right_tbl (that is, all rows in left_tbl with no corresponding row in right_tbl). This assumes that right_tbl.id is declared NOT NULL.

La clause ON est une clause qui permet de renseigner les conditions de jointures des tables. Il n'est pas question de restriction de sélection, juste d'indiquer quels champs permet de les joindre. On constate encore plus l'incohérence de mettre des expressions conditionnelles dans la clause ON quand on utilise à la place la clause USING. Il n'est pas possible d'écrire d'expressions conditionnelles, on ne peut que préciser les colonnes à prendre en compte pour la jointure.

Pour comprendre la différence entre le prédicat de la clause de jointure et le prédicat du filtre WHERE, voyons le petit test suivant :
-- Test de jointure

CREATE TABLE TEST_JOIN1
(COL1 INT,
COL2 CHAR(2));

CREATE TABLE TEST_JOIN2
(COL1 INT,
COL2 CHAR(2));

INSERT INTO TEST_JOIN1 VALUES (101, 'AA');
INSERT INTO TEST_JOIN1 VALUES (102, 'AA');
INSERT INTO TEST_JOIN1 VALUES (103, 'BB');

INSERT INTO TEST_JOIN2 VALUES (101, 'AA');
INSERT INTO TEST_JOIN2 VALUES (102, 'AA');
INSERT INTO TEST_JOIN2 VALUES (201, 'BB');

-- L'équivalence est uniquement une apparence...

SELECT TJ1.COL1, TJ1.COL2
FROM TEST_JOIN1 TJ1
JOIN TEST_JOIN2 TJ2
ON TJ1.COL1 = TJ2.COL1
WHERE TJ1.COL2 = 'AA';

SELECT TJ1.COL1, TJ1.COL2
FROM TEST_JOIN1 TJ1
JOIN TEST_JOIN2 TJ2
ON TJ1.COL1 = TJ2.COL1 AND TJ1.COL2 = 'AA';

-- D'accord... Les résultats sont identiques.

-- On change le lien interne en lien externe...

SELECT TJ1.COL1, TJ1.COL2
FROM TEST_JOIN1 TJ1
LEFT OUTER JOIN TEST_JOIN2 TJ2
ON TJ1.COL1 = TJ2.COL1
WHERE TJ1.COL2 = 'AA';

SELECT TJ1.COL1, TJ1.COL2
FROM TEST_JOIN1 TJ1
LEFT OUTER JOIN TEST_JOIN2 TJ2
ON TJ1.COL1 = TJ2.COL1 AND TJ1.COL2 = 'AA';

-- Les résultats sont différents ! Pourquoi ?

Une chose intéressante aussi est qu'il possible d'obtenir le même résultat que la dernière en faisant :
SELECT TJ1.COL1, TJ1.COL2
FROM TEST_JOIN1 TJ1
LEFT OUTER JOIN TEST_JOIN2 TJ2
ON TJ1.COL1 = TJ2.COL1 AND TJ1.COL2 = 'taratata' AND 1 = 0

So, what the fuck?

La clause WHERE est un filtre d'élimination. Il suppose que les différentes tables sont déjà jointes en une seule et parcourt l'ensemble des résultats à la recherche des lignes correspondant aux critères donnés.

En revanche, la clause JOIN se comporte différemment. Elle agit AVANT que la jointure soit effective.

Dans le cadre d'une jointure interne le comportement est similaire à celui d'une clause WHERE.

Dans le cas d'une jointure externe il faut décomposer la logique en plusieurs étapes :
  1. Évaluation des éléments du prédicat
  2. Application de la jointure : lignes jointe en 1) + lignes sans correspondance

Reprenons la clause de jointure de la requête donnée :
Code :
TJ1.COL1 = TJ2.COL1 AND TJ1.COL2 = 'taratata' AND 1 = 0
   ^^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^     ^^^^^
  prédicat de jointure         prédicats hors jointure

  1. 1 = 0 => aucune ligne n'est récupérée donc aucune ligne de TEST_JOIN1 n'a de correspondance avec TEST_JOIN2
    Conclusion : toutes les lignes de TEST_JOIN1 seront reprises du fait de la jointure externe
  2. TJ1.COL2 = 'taratata' => encore une fois aucune ligne n'est récupérée donc aucune ligne de TEST_JOIN1 n'a de correspondance avec TEST_JOIN2
    Conclusion : toutes les lignes de TEST_JOIN1 seront reprises du fait de la jointure externe
  3. TJ1.COL1 = TJ2.COL1 => 2 lignes sont en correspondance avec TEST_JOIN2
    Conclusion : Ces deux lignes seront récupérées du fait de la jointure externe et la troisième ligne aussi puisqu'elle n'a aucune correspondance



Pour comprendre la différence, il suffit de demander à voir les colonnes de la table TEST_JOIN2 dans les différents cas :
SELECT TJ1.COL1, TJ1.COL2, TJ2.COL1, TJ2.COL2
FROM TEST_JOIN1 TJ1
LEFT OUTER JOIN TEST_JOIN2 TJ2
ON TJ1.COL1 = TJ2.COL1 AND TJ1.COL2 = 'AA'

Code :
COL1        COL2 COL1        COL2
----------- ---- ----------- ----
101         AA   101         AA
102         AA   102         AA
103         BB   NULL        NULL

SELECT TJ1.COL1, TJ1.COL2, TJ2.COL1, TJ2.COL2
FROM TEST_JOIN1 TJ1
LEFT OUTER JOIN TEST_JOIN2 TJ2
ON TJ1.COL1 = TJ2.COL1
WHERE TJ1.COL2 = 'AA'

Code :
COL1        COL2 COL1        COL2
----------- ---- ----------- ----
101         AA   101         AA
102         AA   102         AA

SELECT TJ1.COL1, TJ1.COL2, TJ2.COL1, TJ2.COL2
FROM TEST_JOIN1 TJ1
LEFT OUTER JOIN TEST_JOIN2 TJ2
ON TJ1.COL1 = TJ2.COL1 AND TJ1.COL2 = 'taratata' AND 1 = 0

Code :
COL1        COL2 COL1        COL2
----------- ---- ----------- ----
101         AA   NULL        NULL
102         AA   NULL        NULL
103         BB   NULL        NULL

Voilà.

En bref, au niveau performance, cela ne change rien. Par contre, niveau conceptuel, il est beaucoup plus intéressant de différencier ce qui appartient à la jointure et ce qui appartient à la limitation du jeu de résultat. C'est d'autant plus intéressant que c'est humainement plus maintenable et plus lisible à mesure que la requête est conséquente.

Sources :


RE: [PHP] requêtes dûre - srm - 14-11-2010

Ok Smile