Page 1 sur 1

Alternative au subquery ?

Posté : 28 sept. 2007, 06:20
par Lilian
Bonjour,

je developpe une appli hebergée sur un serveur qui ne propose que du MYSQL 4.0 donc pas de subquery ........ :(
Je cherche donc une alternative à la requete suivante (qui marche très bien avec MYSQL 5.x) :

Code : Tout sélectionner

SELECT * FROM contact_bis WHERE contact_id NOT IN (SELECT contact_id FROM contacts)
le but étant de trouver les records qui ne sont dans la table contact_bis ET pas dans la table contacts.

est ce que quelqu'un à une piste pour résoudre ce problème élégament (sans avoir à faire deux for imbriqués qui impliquerai une compléxité d'ordre n^2)?

merci
lilian

Re: Alternative au subquery ?

Posté : 28 sept. 2007, 08:02
par Hubert Roksor
trouver les records qui ne sont dans la table contact_bis ET pas dans la table contacts.
Je crois que ce que tu voulais dire est "[..] qui sont dans la table contact_bis MAIS pas dans la table contacts."

Si mes souvenirs sont bons, ce type de jointure s'appelle un "anti-join". Tu peux émuler ce type de jointure en mettant "côte à côte" les deux tables avec un LEFT JOIN --contact_bis à gauche, contacts à droite-- et ne garder que les enregistrements qui n'ont pas de correspondance. D'ailleurs, sauf si l'optimizer de MySQL a été changé, ce sera plus efficace que ta requête actuelle.

Code : Tout sélectionner

SELECT cb.* FROM contact_bis cb LEFT JOIN contacts c USING (contact_id) WHERE c.contact_id IS NULL

subquery

Posté : 28 sept. 2007, 15:41
par liliand
bonjour et merci pour cette piste, j'ai réussi à avancer un peu, là j'en suis à :

Code : Tout sélectionner

SELECT contact_bis.contact_id FROM contact_bis LEFT JOIN contacts ON contact_bis.contact_id = contacts.contact_id WHERE contacts.contact_id IS NULL;
et ca marche presque, ca me sort les records qui sont dans contact_bis mais pas dans contacts. Il ne me manque plus qu'à préciser que cette requete ne doit de faire que sur les records dont le champ account_id est égale à une valeur donné.
j'ai essayé :

Code : Tout sélectionner

SELECT contact_bis.contact_id FROM contact_bis LEFT JOIN contacts ON contact_bis.contact_id = contacts.contact_id AND contact_bis.account_id = '59' AND contacts.account_is ='59' WHERE contacts.contact_id IS NULL;
mais ca ca ne marche pas, ca ne me renvoir pas du tout ce que je veux.

je suis preneur de conseil si vous avez ! :)
lilian

Re: subquery

Posté : 28 sept. 2007, 15:57
par Hubert Roksor
Avant toute chose, je te recommande fortement de formatter tes requêtes sur plusieurs lignes. Mettre tout sur la même ligne rend sa lecture difficile et favorise les erreurs. Pour preuve : je viens d'effacer ma réponse précédente parce que j'avais raté certains détails de la requête, à 2/3 coups à de scroll plus loin. C'est aussi pour cela que je recommande très fortement l'usage systématique d'aliases, plutôt que des noms de table à rallonge (trop facile de confondre contacts, contact_bis, contact_prod, contact_rel, etc..., alors qu'en les nommant c, b, p, r, la différence est immédiatement remarquable)

Pour en revenir au sujet,
préciser que cette requete ne doit de faire que sur [???]
Il faudrait que tu postes le schéma de tes tables sous la forme d'une instruction CREATE TABLE.

Posté : 28 sept. 2007, 16:11
par lilian
Voici les tables :

Code : Tout sélectionner

CREATE TABLE `contacts` ( `contact_id` bigint(20) NOT NULL auto_increment, `account_id` varchar(20) NOT NULL default '1', `name` varchar(40) NOT NULL default '', `phone_nbr` varchar(20) NOT NULL default '', UNIQUE KEY `contact_id` (`contact_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=433 ;

Code : Tout sélectionner

CREATE TABLE `contact_bis` ( `contact_id` bigint(20) NOT NULL auto_increment, `account_id` varchar(20) NOT NULL default '1', `name` varchar(40) NOT NULL default '', `phone_nbr` varchar(20) NOT NULL default '', UNIQUE KEY `contact_id` (`contact_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=433 ;
elles sont rigoureusement identiques et servent à stoker des répertoires.
je veux trouver, pour chaque account_id, les records qui sont dans contact_bis mais pas dans contacts

je deprime........... si seulement je pouvais upgrader le serveur à la version 5.0 !! :)

Merci de ton aide
lil

Posté : 28 sept. 2007, 21:05
par Hubert Roksor
Ne déprime pas, il n'y a aucun problème insurmontable en SQL. Tu as une requête qui récupère tous les enregistrements de cb n'ayant pas de correspondance dans c, si tu veux réduire cet ensemble de données tu n'a qu'à ajouter le critère supplémentaire dans ta clause WHERE.

Code : Tout sélectionner

SELECT cb.* FROM contact_bis cb LEFT JOIN contacts c USING (contact_id) WHERE c.contact_id IS NULL AND cb.account_id = 59
Le problème dans ta requête précédente c'est que ta clause WHERE est impossible puisque tu demandes à la fois que l'enregistrement n'existe pas (IS NULL) et que l'enregistrement contienne une donnée (account_id = 59). Les données proviennent de cb, donc c'est sur cb qu'il faut appliquer tes critères supplémentaires.