[SQL] Supprimer les entrées d'1 table selon critère d'1 autre table

Supprimer les entrées d'1 table selon critère d'1 autre table [SQL] - SQL/NoSQL - Programmation

Marsh Posté le 23-04-2009 à 15:26:47    

Bonjour  :hello:  
 
J'ai besoin d'extraire une partie d'une base MySQL pour la mettre en ligne pour la rendre accessible par un site internet. Pour la rendre plus légère et aussi pour des raison de sécurité et de simplicité pour le futur, j'aimerais faire un "nettoyage" de la base et virer toutes les entrées qui ne m'intéressent pas OU que je ne veux pas laisser dispos en ligne.
 
Pour cela, j'aimerais faire 2 requêtes importantes afin de supprimer les entrées d'une table sur un critère basé dans une autre table.
 
Ma BDD est structurée de la façon suivante:  

Citation :

Table (noms des champs)
 
Table1 (id, nom, type)
Table1bis (id, info1, info2)
 
Table2 (id, email1, email2)
Table2bis (id, module, date)


 
La liaison entre TableN et TableNbis se fait par les ID.
 
La première requête que j'aimerais faire consisterait à supprimer toutes les entrées de la Table1 pour lesquelles le champs info1 de la Table1bis est vide (quand je dis vide, ce n'est pas 'NULL' mais un champs qui apparaît blanc).
 
La deuxième requête consisterait à supprimer toutes les entrées de la Table2 pour lesquelles le champs module est 'Users' par exemple.
 
J'ai fait pas mal de recherches, j'ai vu des formules avec des DELETE FROM et des INNER JOIN mais qui ne semblent pas fonctionner. J'ai aussi vu des requêtes avec des DELETE FROM et SELECT IN () mais mes compétences limitées en programmation ne me permettent pas de les construire correctement  :cry:  
 
D'après vous, quelle serait la meilleure option ?
Quelqu'un aurait-il la gentillesse de me donner des exemples des requêtes dont j'ai besoin ?
 
Merci d'avance  :jap:


Message édité par Mariton le 24-04-2009 à 03:48:46
Reply

Marsh Posté le 23-04-2009 à 15:26:47   

Reply

Marsh Posté le 24-04-2009 à 11:28:32    

Utilise la méthode prévue pour spécifier une table de référence sans risquer d'y toucher.
 
DELETE FROM [ ONLY ] table [ [ AS ] alias ]
    [ USING usinglist ]
    [ WHERE condition ]
    [ RETURNING * | output_expression [ AS output_name ] [, ...] ]
 
usinglist  
A list of table expressions, allowing columns from other tables to appear in the WHERE condition. This is similar to the list of tables that can be specified in the FROM Clause of a SELECT statement; for example, an alias for the table name can be specified. Do not repeat the target table in the usinglist, unless you wish to set up a self-join.
 
 
 

Code :
  1. DELETE FROM table1
  2. USING table1bis
  3. WHERE table1.id      =table1bis.id
  4. AND   table1bis.info =''
  5. et
  6. DELETE FROM table2
  7. USING table2bis
  8. WHERE table2.id        =table2bis.id
  9. AND   table2bis.module ='Users'


 
 
 
Note évite de mettre des majuscules dans le nom de tes tables, c'est une bonne habitude à prendre (comportements différents selon les SGBD)


Message édité par robbyone le 24-04-2009 à 12:49:11
Reply

Marsh Posté le 24-04-2009 à 12:07:30    

Bonjour,
 
La syntaxe que j'aurai utilisé serait :  
 
DELETE FROM TABLE1 T1
INNER JOIN TABLE1BIS T1B ON T1B.id = T1.id
WHERE T1B.info = ''
 
Si ça ne passe pas, tu peux essayer de faire :  
 
DELETE FROM TABLE1
WHERE id IN (
    SELECT id FROM TABLE1BIS
    WHERE TABLE1BIS.info1 = ''
    )
 
Dans tous les cas, avant de lancer tes DELETE, je te conseil de faire un SELECT * à la place, pour valider que les lignes sélectionnées sont les bonnes. Une fois que c'est validé, tu déclenches une transaction (sur SQL Server c'est BEGIN TRAN nom_de_la_transaction), puis tu executes ta requête de DELETE, et si le nombre de lignes affectées correspond à ce que tu attendais avec ton SELECT *, tu valides ta transaction avec un COMMIT TRAN nom_de_la_transaction.
 
J'oubliais, attention aux contraintes d'intégrité avant de faire le DELETE, ça va poser problème si tu as des données liées à ta tables TABLE1 (il faudra dans ce cas supprimer toutes les données liées à ces lignes dans les tables liées avant de pouvoir nettoyer la table TABLE1).
 
Bon courage,


Message édité par Tibar le 24-04-2009 à 12:09:59
Reply

Marsh Posté le 24-04-2009 à 13:22:39    

quelle version de mysql?


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 27-04-2009 à 12:06:27    

Bonjour,
 
Merci a tous pour votre aide :)
Je vais regarder vos solutions rapidement et vous tiendrai au courant.
 
@rufo: je tourne sous MySQL 5.1.33 ;)

Reply

Marsh Posté le 28-04-2009 à 14:11:59    

Bonjour à tous,
 
Je viens d'essayer les plusieurs solutions qui m'ont été proposées et il semblerait que la 2e syntaxe donnée par Tibar qui soit la bonne.
 

Citation :

DELETE FROM TABLE1
WHERE id IN (
    SELECT id FROM TABLE1BIS
    WHERE TABLE1BIS.info1 = ''
    )


 
Cependant, quand je l'exécute, toutes mes entrées de la table1 sont supprimées (même celles pour lesquelles TABLE1BIS.info1 contient des données) ce qui est apparemment dû au fait qu'on est un = ''  et qui ne fonctionne pas dans mon cas puisque j'imagine que c'est interprété de la même façon qu'un '*' dans un requête SELECT par exemple.
 
J'ai essayé avec = NULL mais ça ne donne rien (aucun suppression car aucun champs n'est null, ils sont soit blancs, soit avec une expression.
Y'aurai-til un moyen de contourner cela (soit par une requete intermédiaire qui convertirait les blancs en NULL, soit par une expression dans l'égalité qui permet de ne prendre que les blancs?  :??:  
 
Merci d'avance :)
 

Reply

Marsh Posté le 28-04-2009 à 14:14:08    

= null je crois ne marche pas
il faut faire" WHERE TABLE1BIS.info1 is null"

Reply

Marsh Posté le 28-04-2009 à 17:55:17    

= null ne fonctionne pas, je confirme que c'est is null qu'il faut utiliser.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 29-04-2009 à 14:35:36    

Salut,
 
En fait je pense que j'ai été un peu induit en erreur par ta précision :
"quand je dis vide, ce n'est pas 'NULL' mais un champs qui apparaît blanc"
du coup j'ai raccourci en prenant comme critère la chaine vide...
Comme je te le disais, le plus simple c'est que tu fasses le SELECT avec le critère qui te convient, et tu places cette partie dans le WHERE de la sous-requête, au moins tu n'auras pas de mauvaise surprise...
 
Bon courage,

Reply

Marsh Posté le 04-05-2009 à 13:47:29    

Bonjour à tous,
 
Alors j'ai fait plusieurs tests et je n'arrive toujours pas à sélectionner les blancs pour les supprimer.
 
J'ai testé:  

Citation :

DELETE FROM `table1`
WHERE id IN (
    SELECT id FROM `table1bis`
    WHERE `table1bis`.`info1` = ''
    )


 
Dans ce cas, toutes les lignes sont sélectionnées (même cas que précédemment)
 
Si je remplace = '' par IS NULL, aucune ligne n'est sélectionnée (normal, les champs ne sont pas NULL mais bien vides ou blancs, appelez ça comme vous voulez).
 
Par contre, quand je fais une recherche générée avec PHPMyAdmin avec la formule suivante:

Citation :

SELECT *
FROM `table1bis`
WHERE `info1` = ''
LIMIT 0 , 30


Étonnamment, il ne me sélectionne que les lignes donc le champs info est effectivement blanc ou vide.
 
Comment expliquer que le = '' fonctionne pour un SELECT FROM simple sur la table en question et qu'il ne fonctionne pas sur un DELETE FROM (avec lien entre les 2 tables)?
 
Y'aurait-il une solution ou une alternative à ça (genre une opération intermédiaire permettant de faire le tri ou de remplacer les blancs par NULL) ?
 
Merci d'avance :jap:

Reply

Marsh Posté le 04-05-2009 à 13:47:29   

Reply

Marsh Posté le 04-05-2009 à 19:35:03    

Salut,
 
Si tu fais  
SELECT * FROM TABLE1
WHERE TABLE1.id IN (  
    SELECT id FROM `table1bis`  
    WHERE `table1bis`.`info1` = ''  
    )  
 
ca te ressort des lignes ou pas ?
 
Pour faire un test, tu peux essayer avec les fonctions LTRIM et RTRIM, ça supprime les "blancs" en début et/ou en fin de chaine, par exemple si tu fais LTRIM(RTRIM('   TEST   ')), ça te sort 'TEST', ça peut peut-être éviter de se tracasser avec la chaine vide, surtout si elle peut être composée de "blancs".
 
Si tout ça ne fonctionne pas, le plus simple, je pense, serait de selectionner tous les id présents dans la table TABLE1BIS que tu veux supprimer, en faisant :  
 
INSERT INTO ID_A_EFFACER
SELECT DISTINCT id
FROM TABLE1BIS
WHERE info1 = ''  
(ou WHERE LTRIM(RTRIM(info1)) = '' si tu as des problèmes avec le champ info1)
 
Je ne suis pas sur de la syntaxe du INSERT INTO... SELECT... en mysql, mais tu dois pouvoir trouver des infos la dessus...
 
Dans tous les cas, c'est assez bizarre que ton DELETE n'aie pas le même comportement que le SELECT...
Je pourrais essayer la syntaxe demain,
 
Bon courage,

Reply

Marsh Posté le 05-05-2009 à 11:55:09    

Bonjour,

 

Merci Tibar pour ton aide très appréciable :jap:

 

Alors j'ai approfondi mes tests et recherches sur ce problème, il semblerait que le comportement de SELECT ou de DELETE soit différent à partir du moment ou la requête devient "composée" (avec des conditions telles que celles essayées plus haut).
Si je fais un SELECT simple sur Table1bis avec = '' en critère, il me sélectionne bien les champs que je veux supprimer, lorsque que j'utilise ce même critère sur un SELECT avec plusieurs conditions type WHERE IN () etc..., alors il me sélectionne toutes les lignes sans faire la différence.

 

Du coup, je me suis dit que c'était peut-être le = '' qui ne passait pas bien dans un requête "complexe" alors j'ai fait un UPDATE de ma table1bis pour convertir toutes les lignes dont le info1 est vide en '0'

Citation :

UPDATE `Table1bis`
SET `info1` = 0
WHERE `info1` = ''

 

Ca a marché sans aucun soucis.
Maintenant, si je refais une requête SELECT composée en changeant le vide par le 0 comme suit:

Citation :

SELECT * FROM `table1`
WHERE id IN (
    SELECT id FROM `table1bis`
    WHERE `table1bis`.`info1` = '0'
    )


le problème revient, toutes les lignes sont sélectionnées sans tenir compte du critère = '0' :(

 

Faut croire que la synthaxe est exécutable mais ne permet pas d'obtenir exactement le résultat voulu :/
Quelqu'un aurait-il une autre idée de synthaxe pour parvenir au résultat attendu?

 

Au passage, j'ai plusieurs centaines d'entrées donc je me vois mal faire un tri manuellement :whistle:

 

Merci d'avance :)

 


Message édité par Mariton le 05-05-2009 à 11:56:52
Reply

Marsh Posté le 05-05-2009 à 13:18:26    

essaye avec
WHERE `table1bis`.`info1` like '0'
 

Reply

Marsh Posté le 05-05-2009 à 15:28:28    

Pas de problème, par contre je ne comprends pas du tout ce qui se passe...
Je viens de faire le test sur une base MySQL, avec les 2 versions de ma requête (INNER JOIN ou IN) et j'obtiens bien le bon resultat à chaque fois, que ce soit en SELECT ou en DELETE.
Pour essayer "à la main", tu pourrais faire :  
SELECT CONCAT(TABLE1BIS.info1, ',')
FROM TABLE1BIS
WHERE INFO1 = '' (ou ton nouveau critère, si tu l'as passé à '0' par exemple).
Ca va te sortir, normalement, un resultat du type :  
id1,
id2,
idi,
...
idx,
 
Tu copies tous ces id, tu supprimes la dernière virgule, et tu relances ton
DELETE
FROM TABLE1
WHERE Id IN
(
tu colles ici la liste des id récupérés au dessus
)
 
Si ça fonctionne, je ne comprendrai pas grand chose mais tant mieux, par contre, si ça ne fonctionne pas, ça me rassurerait, ça voudrait dire qu'il y a eu un problème d'analyse sur ta première demande...
 
Bon courage,

Reply

Marsh Posté le 07-05-2009 à 04:54:00    

Merci Tibar :)
 
Je viens d'essayer le SELECT CONCAT tel que tu me l'as présenté et j'obtiens bien une liste des entrées concernées (celle avec le critère '0') mais cette liste rapporte le contenu du champ info1 (c'est à dire 0, 0, 0, 0...) et non le numéro de l'id de la ligne concernée. Après vérification, je viens de voir que la requête ne spécifie rien vis-à-vis du champ ID dont on veut la liste donc je suppose qu'il y a une petite manip à ajouter pour avoir les ID en résultat plutôt que le contenu de info1 ? :??:


Message édité par Mariton le 07-05-2009 à 04:55:08
Reply

Marsh Posté le 07-05-2009 à 11:40:35    

Bonjour,
 
En effet, j'ai fait une erreur dans ma requête...
Il faut que tu fasses un SELECT CONCAT(TABLE1BIS.id, ',')
plutôt que SELECT CONTACT(TABLE1BIS.info1, ',')
 
Désolé et bon courage,
 

Reply

Marsh Posté le 07-05-2009 à 12:20:36    

Merci encore Tibar :jap:
 
J'aurais pu la trouver moi-même la dernière si j'avais réfléchi 2sec :sarcastic:
 
Enfin bref, tout ça pour dire que je n'ai pas eu à tester cette alternative car j'ai trouvé ce qui n'allait pas! En fait, il y avait une légère différence dans le nom des champs ID entre la table1 et la table1bis (dans la table1bis, le champs de l'ID s'appelle "id_c" et non "id" ). Ca explique pourquoi ca ne marchait pas et évidemment, j'ai pas percuté tout de suite :sarcastic:  
 
Merci donc à tous ceux qui m'ont aidé et désolé pour mon manque de rigueur !
 

Reply

Marsh Posté le 07-05-2009 à 15:27:24    

Ok, ça explique un peu ces galères... Je ne sais pas si tu donnais les vrais noms de tes tables dans les exemples sur le forum ou si tu donnais des exemples, mais si ce sont les vrais noms (de champs et de tables), il faudrait peut-être essayer de trouver une règle de nommage un peu plus "logique" que juste "id", sinon quand tu vas te retrouver à faire des requêtes un peu plus complexes, avec plusieurs jointures, ça risque de t'emmêler pas mal... mais c'est un autre sujet...
 
Bonne continuation,


Message édité par Tibar le 07-05-2009 à 15:27:45
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed