2010-04-15 7 views
1

J'ai une base de données avec trois tables:Comment réparer cette requête SQL simple?

  • user_table
  • country_table
  • city_table

Je veux écrire ANSI SQL qui me permettra de récupérer toutes les données utilisateur (c.-à-utilisateur détails incluant le nom du pays de la dernière école et le nom de la ville où ils habitent maintenant). Le problème que j'ai est que je dois utiliser une auto-jointure, et je suis un peu confus.

Le schéma est illustré ci-dessous:

CREATE TABLE user_table (id int, first_name varchar(16), last_school_country_id int, city_id int); 

CREATE TABLE country_table (id int, name varchar(32)); 

CREATE TABLE city_table (id int, country_id int, name varchar(32)); 

Ceci est la requête que je suis venu avec jusqu'à présent, mais les résultats sont mauvais, et parfois, le moteur db (mySQL), me demande si je veux pour montrer tous les résultats [ÉNORME NUMÉRO HERE] - ce qui me fait penser que je crée involontairement un produit cartésien quelque part. Est-ce que quelqu'un peut expliquer ce qui ne va pas avec cette instruction SQL, et ce que je dois faire pour le réparer?

SELECT usr.id AS id, usr.first_name, ctry1.name as loc_country_name, ctry2.name as school_country_name, city.name as loc_city_name 
       FROM user_table usr, country_table ctry1, country_table ctry2, city_table city 
       WHERE usr.last_school_country_id=ctry2.id 
         AND usr.city_id=city.id 
         AND city.country_id=ctry1.id 
         AND ctry1.id=ctry2.id; 
+1

Êtes-vous sûr que 'ctry1.id = ctry2.id' est correct? –

+0

Vous n'avez pas besoin d'une auto-jointure, et vous en utilisez une, mais cela ne vous apporte rien de nouveau. Êtes-vous en train de dire que vous «devez utiliser une auto-adhésion» parce que cela fait partie de la mission? – MJB

+0

@MJB: mon SQL peut être rouillé, mais je pense que j'ai besoin d'une auto-participation. La raison en est que le pays de l'école et le pays actuel (dérivé de la ville actuelle) peuvent être différents. – morpheous

Répondre

1

Essayez ceci. Je l'ai écrit en utilisant la syntaxe ANSI pour plus de clarté. Je suppose que vous ne pouvez pas toujours avoir usr.city_id ou usr.last_school_country_id, donc j'ai utilisé un left outer join ce qui signifie que vous obtiendrez toujours usr enregistrements indépendamment.

J'ai également supprimé and ctry1.id=ctry2.id, car cela nécessiterait que la ville actuelle de l'utilisateur soit dans le même pays que leur last_school_country_id, ce que je ne pense pas toujours être le cas.

SELECT usr.id AS id, usr.first_name, ctry1.name as loc_country_name, ctry2.name as school_country_name, city.name as loc_city_name 
FROM user_table usr 
left outer join city_table city on usr.city_id=city.id 
left outer join country_table ctry1 on city.country_id=ctry1.id 
left outer join country_table ctry2 on usr.last_school_country_id=ctry2.id 
+0

très bon exemple. J'ai finalement obtenu un exemple concret de «JOIN» qui me semble logique. Je comprend maintenant. JE VOUS REMERCIE. Merci aussi d'EXPLIQUER comme vous l'avez fait. J'ai accepté votre réponse. – morpheous

+0

Heureux d'aider :) – RedFilter

0

normalement si vous vous joignez à 3 tables, il y aura deux déclarations d'assemblage. toujours 1 de moins que le nombre d'éléments à joindre.

Peu importe, je comprends pourquoi vous pourriez avoir besoin de la jointure, va continuer à travailler au code.

SELECT user_table.*, contry_table.*, city_table.* FROM user_table, country_table, city_table WHERE country_table.id = last_school_country_id AND city_id = city_table.id 
0

Cette requête sélectionne tous les utilisateurs dont la ville est dans le même pays que leur dernière école:

SELECT usr.id AS id, usr.first_name, ctry1.name as loc_country_name, ctry2.name as school_country_name, city.name as loc_city_name 
FROM user_table usr 
JOIN city 
ON  city.id = usr.city_id 
JOIN country_table ctry1 
ON  ctry1.id = city.country_id 
JOIN country_table ctry2 
ON  ctry2.id = usr.last_school_country_id 
WHERE ctry1.id = ctry2.id 

Il est synonyme de votre requête initiale.

Tant que tous les champs nommés id sont des clés primaires, cette requête ne peut pas renvoyer plus d'enregistrements que dans user_table.

Assurez-vous que tous les id sont PRIMARY KEY s et vous n'avez pas de doublons.

Pourriez-vous s'il vous plaît exécuter ces requêtes:

SELECT COUNT(*) 
FROM user_table 

SELECT COUNT(*), COUNT(DISTINCT id) 
FROM city 

SELECT COUNT(*), COUNT(DISTINCT id) 
FROM country_table 

et après la sortie ici?

+0

Qu'en est-il des cas où la dernière école de l'utilisateur était dans un pays différent? – morpheous

+0

@morpheous: Je ne sais pas quoi sur ces cas: je viens de réécrire votre requête originale. Si vous n'avez pas besoin de ce filtre, supprimez la clause 'WHERE'. – Quassnoi