données dans une table et pas dans une autre

Invité
Invité n'ayant pas de compte PHPfrance

25 déc. 2007, 14:39

Bonjour,

Je dispose de deux tables MySQL ( "table1" et "table2" ) qui ont la même structure.
Elles n'ont qu'un seul champ "valeur".

Je cherche une requête SQL qui liste toutes les valeurs qui sont présentes dans le champ "valeur" de "table1" et absentes du champ "valeur" de "table2".

Je n'arrive pas à trouver cette requête.

Si quelqu'un pouvait m'aider ...
Merci d'avance

et bonnes fêtes !!

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

25 déc. 2007, 14:45

Je n'arrive pas à trouver cette requête.
T'as regardé sous le canapé ?

Plus sérieusement, si tu souhaites recevoir de l'aide il te faut d'abord respecter les consignes du forum. Pour rappel :
Rappel pratique - n'oubliez pas de :
  1. suivre ces quelques conseils de débogage
  2. préciser quel SGBD vous utilisez ainsi que sa version
  3. utiliser les balises

    Code : Tout sélectionner

    [/i] et [i]
    [/i] pour afficher vos requêtes SQL
  4. poster le schéma des tables pertinentes à votre requête sous la forme d'une instruction "CREATE TABLE" (fonction "Exporter" de phpMyAdmin)
  5. si nécessaire, poster un échantillon des données
Attention, suivre ces consignes est obligatoire. Merci de les lire attentivement.

Invité
Invité n'ayant pas de compte PHPfrance

25 déc. 2007, 15:44

T'as regardé sous le canapé ?
Ben pour une fois que je pose une question sur un forum ...

je vais essayer d'en respecter les consignes :
1. suivre ces quelques conseils de débogage
je n'ai pas de code, donc rien à déboguer.
2. préciser quel SGBD vous utilisez ainsi que sa version
comme précisé dans le premier post il s'agit de 2 tables MySQL
3. utiliser les balises et pour afficher vos requêtes SQL
je n'avais pas de code à afficher.
4. poster le schéma des tables pertinentes à votre requête sous la forme d'une instruction
comme précisé dans le premier post ces 2 tables MySQL ont la même structure et ont un seul champ nommé "valeur" ( c'est pour simplifier, en fait elles en ont plusieurs )
CREATE TABLE `table1` (
`valeur` TEXT NOT NULL
);

CREATE TABLE `table2` (
`valeur` TEXT NOT NULL
);
5. si nécessaire, poster un échantillon des données
ok,
dans "table1" , on trouve dans le champ "valeur" : a,b,c,d
dans "table2" , on trouve dans le champ "valeur" : a,c

j'aimerais que la requête ( si elle existe ) sorte les valeurs : b,d
( comme précisé dans le premier post : toutes les valeurs qui sont présentes dans le champ "valeur" de "table1" et absentes du champ "valeur" de "table2".)

je ne sais même pas si c'est possible avec une requête.
d'où ma question sur ce forum

Invité
Invité n'ayant pas de compte PHPfrance

25 déc. 2007, 17:10

dans mon précédent message, ce n'était pas clair.

dans "table1" :
valeur
a
b
c
d

dans "table2" :
valeur
a
c

Eléphant du PHP | 185 Messages

25 déc. 2007, 17:16

Une requête de type SELECT me semble adaptée à ta recherche...

Code : Tout sélectionner

SELECT valeur.table1, valeur.table2 FROM table1, table2 WHERE valeur.table1 <> valeur.table2
Essaie ça !

Bon, je retourne cuver mon vin... :P

Invité
Invité n'ayant pas de compte PHPfrance

25 déc. 2007, 19:06

Kaoteknik, je bois à ta santé !

tu as sans doute voulu dire :
SELECT table1.valeur, table2.valeur FROM table1, table2 WHERE table1.valeur <> table2.valeur

pour l'instant je n'y arrive pas, je verrai demain dans de meilleures conditions ...

merci pour ta réponse, joyeux noël à nous tous !

Eléphant du PHP | 185 Messages

25 déc. 2007, 19:27

En effet, j'ai inversé... J'ai besoin de sommeil aussi !

ViPHP
ViPHP | 5924 Messages

25 déc. 2007, 22:47

2. préciser quel SGBD vous utilisez ainsi que sa version
comme précisé dans le premier post il s'agit de 2 tables MySQL
Alors je pense que nous ne lisons pas la même chose, puisque dans la phrase, si je ne me trompe, l'on demande le "SGDB ainsi que sa version"
Tu peux trouver superflu de donner la version, mais on ne fait pas la même chose avec un MySQL 4.0 et un MySQL 4.1 … :-/
4. poster le schéma des tables pertinentes à votre requête sous la forme d'une instruction
comme précisé dans le premier post ces 2 tables MySQL ont la même structure et ont un seul champ nommé "valeur" ( c'est pour simplifier, en fait elles en ont plusieurs )
CREATE TABLE `table1` (
`valeur` TEXT NOT NULL
);

CREATE TABLE `table2` (
`valeur` TEXT NOT NULL
);
5. si nécessaire, poster un échantillon des données
ok,
dans "table1" , on trouve dans le champ "valeur" : a,b,c,d
dans "table2" , on trouve dans le champ "valeur" : a,c
Alors permet moi de te dire que tu as là une très très très mauvaise modélisation. Une base de données, ce n'est pas un fichier texte, ce qui signifie que tu ne parcoures pas les données d'un champ aussi facilement que dans un fichier texte, et qu'au contraire, si tu utilises bien ta base du peux faire 100 fois plus de choses.
Dans ton cas, lorsque tu stockes a,b,c,d dans un même enregistrement, ce sont des données que tu ne peux plus traiter, alors que si tu avais ms a dans un enregistrement, b dans un autre, c dans un autre encore, et enfin d dans un dernier, tu pouvais faire des opérations dessus via des requètes SQL, mais là c'est dommage, parce qu'on ne va pas pouvoir t'aider.
Je t'invite donc fortement à revoir ton schéma, et au besoin à nous demander des conseils pour le refaire…

Invité
Invité n'ayant pas de compte PHPfrance

25 déc. 2007, 23:54

bonsoir,
Alors je pense que nous ne lisons pas la même chose, puisque dans la phrase, si je ne me trompe, l'on demande le "SGDB ainsi que sa version"
Tu peux trouver superflu de donner la version, mais on ne fait pas la même chose avec un MySQL 4.0 et un MySQL 4.1 … :-/
Je fais des tests sur une vieille version : 4.1.9
Au final ce sera sur une version 5.0.45
alors que si tu avais ms a dans un enregistrement, b dans un autre, c dans un autre encore, et enfin d dans un dernier, tu pouvais faire des opérations dessus via des requètes SQL
c'est exactement ce que j'ai.
( c'est ce que j'ai voulu exprimer maladroitement à 17h10 )

je suis venu en paix chez PHPFrance, si ma question doit énerver tout le monde, merci de supprimer le sujet.

ViPHP
ViPHP | 5924 Messages

26 déc. 2007, 00:33

Non, mais je te fais juste comprendre que mal venir poser sa question, c'est perdre le temps aussi bien de nous que de toi.
Et entre autres la version du SGBD est très importante puisque les moyens d'arriver au résultat diffèreront d'une version à l'autre, je te conseille donc de faire tes tests sur la même version que le serveur de production (ou du moins la même version x.x).

Donc pour répondre à ta question, je dirais :

Code : Tout sélectionner

SELECT valeur FROM table1 WHERE valeur NOT IN(SELECT valeur FROM table2);
Cette solution marchera sur les versions supérieures ou égales à 4.1 (si j'en crois un message il y a peu disant que les sous requètes sont disponibles sur la 4.1), la solution précédemment donnée ne fonctionnera pas (et j'ai la flemme d'expliquer pourquoi :-/ ).

ViPHP
ViPHP | 5924 Messages

26 déc. 2007, 00:38

Vérification en images (pour le test, j'utilise un VARCHAR(255) et le serveur est un 5.0.45 MySQL Community Server) :

Code : Tout sélectionner

mysql> CREATE TABLE test1(valeur VARCHAR(255) NOT NULL PRIMARY KEY); Query OK, 0 rows affected (0.09 sec) mysql> CREATE TABLE test2(valeur VARCHAR(255) NOT NULL PRIMARY KEY); Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO test1 VALUES("a"),("b"),("c"),("d"); Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> INSERT INTO test2 VALUES("a"),("c"); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> SELECT valeur FROM test1 WHERE valeur NOT IN(SELECT valeur FROM test2); +--------+ | valeur | +--------+ | b | | d | +--------+ 2 rows in set (0.00 sec)

Invité
Invité n'ayant pas de compte PHPfrance

26 déc. 2007, 11:59

Code : Tout sélectionner

SELECT valeur FROM table1 WHERE valeur NOT IN(SELECT valeur FROM table2);
cette requête fonctionne parfaitement avec MySQL 4.1.9

Sékiltoyai, merci beaucoup pour ton aide et pour tout le temps que tu as consacré à mon problème.

( N'étant pas enregistré, je ne peux pas mettre la marque [résolu] )

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

26 déc. 2007, 11:59

@Guest : je crois qu'on est parti du mauvais pied alors je vais clarifier. Le but de PHPFrance, et du forum SQL, n'est pas de "trouver la réponse" comme si c'était la télécommande du DVD, planquée entre les coussins du canapé. Le vrai but c'est de permettre aux utilisateurs de comprendre leur problème pour y apporter une solution. Et c'est pour cela que l'on demande des informations sur ledit problème, telles que le schéma exactes des tables ou la nature exacte des données, car sans ces informations on ne peut que deviner. Ou alors, pour être complet, expliquer toutes les variations possibles de chaque problème, ce qui est bien entendu impossible.

Dans le cas présent, je comprends qu'il s'agit de joindre deux tables. Si le schéma présenté est exact (ce que je doute) alors je prévois que tu vas connaître des problèmes de performances, parce que les tables ne possèdent pas d'index. Ces problèmes seront aggravé par l'utilisation de colonnes de type TEXT, très différent par nature du type CHAR/VARCHAR. Je vois que tu as posté un échantillon de données, si toutes tes données consistent en une seule lettre alors je te recommande de changer le type en CHAR(1), bien plus rapide.

La solution de Sékiltoyai, que je remercie d'avoir posté ses données sous la formes d'instructions INSERT, devrait fonctionner correctement. Ceci dit, je ne conseille pas l'utilisation de sous-requêtes dans un comparateur IN si les tables possèdent de nombreux enregistrement, à moins d'utiliser MySQL 6.0 (comme quoi, les versions...). En fait, même sous 6.0 je ne suis pas certain que l'optimiseur ait été mis à jour. Dans l'état actuel des choses, MySQL considère ces requêtes comme des DEPENDENT SUBQUERY et par conséquent exécute une requête sur la table "intérieure" pour chacune des lignes de table "extérieure".

Comme le manuel le suggère, je recommanderais donc d'utiliser une jointure plutôt qu'une sous-requête, eg

Code : Tout sélectionner

SELECT t1.valeur FROM test1 t1 LEFT JOIN test2 t2 USING (valeur) WHERE t2.valeur IS NULL

ViPHP
ViPHP | 5924 Messages

26 déc. 2007, 12:44

En fait, même sous 6.0 je ne suis pas certain que l'optimiseur ait été mis à jour. Dans l'état actuel des choses, MySQL considère ces requêtes comme des DEPENDENT SUBQUERY et par conséquent exécute une requête sur la table "intérieure" pour chacune des lignes de table "extérieure".
Ok, je ne connaissais pas cette subtilité…

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

26 déc. 2007, 13:10

Si tu as du temps à perdre, voici un peu de lecture sur le sujet ;)

http://forge.mysql.com/worklog/task.php?id=2980
http://forge.mysql.com/worklog/task.php?id=1110
http://forge.mysql.com/worklog/task.php?id=3830

(ce sont des docs techniques TL;DR)