Comparer le count de la requête?

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Comparer le count de la requête?

par cicom » 19 mai 2008, 21:57

Salut,
Beaucoup plus léger que ma méthode (normal avec une requête en moins par itération..) surtout quand on enlève une partie de l'affichage (mais je t'en remercie, cet affichage m'a permis de contrôler le bon fonctionnement sur mon server test)
En plusieurs exécutions je devrais arriver à nettoyer ma base de données plus vite.
Je mets au défit qui que ce soit de faire dans la même simplicité et aussi léger.
Merci à tous de votre aide!
EDIT mon server principal y est arrivé en une seule exécution contre 18 pour mon server test.
De plus j'avais fait 14 exécutions(11000 enregistrements supprimés sur 38000) de mon scripts sur le server principal sans être arrivé au bout, bien joué donc Rami, je mets résolu

par rami » 19 mai 2008, 19:45

L'article de développez.com fournit une manière élégante de supprimer les doublons. Si j'avais à le faire désormais, j'utiliserais cette méthode.
Néanmois, n'aimant pas resté sur un échec, voilà une solution (testée) qui a l'air de fonctionner.
J'ai corrigé la 1ere requête pour que le count() soit correct :

Code : Tout sélectionner

mysql> use test; Database changed mysql> SELECT * FROM pub; +----+------+--------+ | id | camp | pseudo | +----+------+--------+ | 1 | 226 | cicom | | 2 | 227 | cicom | | 3 | 226 | cicom | | 4 | 225 | cicom | | 5 | 226 | cicom | | 6 | 227 | cicom | | 7 | 226 | cicom | +----+------+--------+ 7 rows in set (0.00 sec) mysql> SELECT count(id) AS compte, t1.camp, t1.pseudo FROM pub t1 GROUP BY pseudo,camp HAVING (compte > 1); +--------+------+--------+ | compte | camp | pseudo | +--------+------+--------+ | 4 | 226 | cicom | | 2 | 227 | cicom | +--------+------+--------+ 2 rows in set (0.00 sec)
Il ne reste plus qu'à supprimer une ligne de moins que le count() :
<?php
$sql1 = mysql_query("SELECT count(id) AS compte, t1.camp, t1.pseudo FROM pub t1 GROUP BY pseudo,camp HAVING (compte > 1)") or die(mysql_error());
while($sql2 = mysql_fetch_array($sql1, MYSQL_ASSOC) )
{
    echo '<pre>' . print_r($sql2, 1) . '</pre>';
    echo '<br />'.$sql2['compte'].' id '.$sql2['id'].' '.$sql2['pseudo'].' <br />';
    if($sql2['compte'] > 1 )
    {
        $delCount = $sql2['compte'] - 1;
        echo '<br />Suppression de '. $delCount . ' '. $sql2['pseudo'] . ' ' . $sql2['camp'] ;
        $sql = "DELETE FROM pub WHERE pseudo = '".$sql2['pseudo']."' AND camp = ".$sql2['camp'] . " LIMIT $delCount";
        echo "<br />$sql";
        mysql_query( $sql );
    }
}
echo 'opération effectuée';
J'attends vos retours ;)

par cicom » 19 mai 2008, 18:40

Salut à tous!
Merci de vos nombreuses réponses!
A HyWaN => Merci pour ton lien, très intéressant mis à part que je n'ai pas encore vu la notion de procédure dans la bdd (faudrait que je m'achète un bon gros bouquin sur le SQL histoire d'avoir des connaissances pro sur le SQL (un peu plus que jointure, création, insert, update, delete et constraint quoi...)
A Victor => Bien évidement que la table est mal conçue c'est sur ce site que j'ai fait mes tous premiers pas en php sql etc..., d'ailleurs les deux tiers de mes messages sur ce forum doivent le concerner...
On a déjà essayé ton système mais le count avec la jointure compte un peu n'importe quoi, du coup le delete me supprime tout en bloc...
A Cyrano => Cette opération ne sera-t-elle pas plus lourde que celle que j'effectue déjà?
Merci à tous!

par Hywan » 19 mai 2008, 09:07

En une seule requête, je doute que ce soit faisable. Pour ma part, le seul truc que je vois, ce serait de passer par une table temporaire pour y stocker chaque occurrence unique, vider la table d'origine et d'y ré-injecter le contenu de la table temporaire. :-k
Un peu comme j'avais dis de faire en deux requêtes quoi …

par Cyrano » 19 mai 2008, 06:27

En une seule requête, je doute que ce soit faisable. Pour ma part, le seul truc que je vois, ce serait de passer par une table temporaire pour y stocker chaque occurrence unique, vider la table d'origine et d'y ré-injecter le contenu de la table temporaire. :-k

par Victor BRITO » 19 mai 2008, 01:28

Salut,
Je veux supprimer dans ma table tous les doublons sur le champ camp et le champ pseudo en laissant un enregistrement uniquement à chaque fois.
exemple si dans ma db j'ai ('','226','cicom');('','227','cicom');('','226','cicom');('','225','cicom');('','226','cicom');('','227','cicom');('','226','cicom')
je veux qu'il reste
('','226','cicom');
('','227','cicom');
('','225','cicom');
L'ordre des id n'ayant pas d'importance.
Merci de votre aide!
Je vois qu'on a affaire à une table mal conçue, en ce sens que l'on pouvait dès le départ créer des clés d'index unique sur la(les) colonne(s) concernées.

Pour remédier à ton problème, il faudrait appliquer la requête suivante :

Code : Tout sélectionner

SELECT COUNT(id) FROM ta_table WHERE id='226'
récupérer le nombre retourné pour exécuter la requête suivante :

Code : Tout sélectionner

DELETE FROM ta_table WHERE id='226' LIMIT n-1
en remplaçant n-1 par le résultat de la soustraction de 1 du nombre retourné, sous peine d'erreur de syntaxe.

par Hywan » 19 mai 2008, 00:00

par cicom » 18 mai 2008, 23:05

Salut,
Je veux supprimer dans ma table tous les doublons sur le champ camp et le champ pseudo en laissant un enregistrement uniquement à chaque fois.
exemple si dans ma db j'ai ('','226','cicom');('','227','cicom');('','226','cicom');('','225','cicom');('','226','cicom');('','227','cicom');('','226','cicom')
je veux qu'il reste
('','226','cicom');
('','227','cicom');
('','225','cicom');
L'ordre des id n'ayant pas d'importance.
Merci de votre aide!

par Cyrano » 18 mai 2008, 22:22

J'ai personnellement un peu de mal à saisir ce que tu veux supprimer.

Essaye de formuler dans tes mots (donc en français et non en SQL) selon quelles conditions tu veux supprimer des lignes dans quelle table : si ta formulation est correcte, il restera juste à la traduire en SQL après, ce sera infiniment plus facile :-k

par cicom » 18 mai 2008, 22:13

Salut rami,
J'ai déjà essayé un truc similaire mais ca me supprimait tout en bloc (il compte chaque truc tro pde fois je ne sais pas pourquoi...)
Merci de ton aide!

par rami » 18 mai 2008, 21:39

Il me semble que "AS" est optionnel pour le renommage des tables en SQL ANSI, mais j'avoue ne pas avoir eu le courage de vérifier...

En ce qui concerne ton problème cicom, essaies de supprimer une ligne de moins que la somme trouvée par le count :
<?php
include ('gs_includes/scripts.php');
$sql1 = mysql_query("SELECT count(t1.id) AS compte, t1.camp, t1.pseudo, t1.id FROM pub t1 JOIN pub t2 ON ( t1.pseudo = t2.pseudo AND t1.camp = t2.camp AND t1.id <> t2.id ) WHERE t1.camp = '227' GROUP BY pseudo HAVING (compte > 1)") or die(mysql_error());
while($sql2 = mysql_fetch_array($sql1, MYSQL_ASSOC))
{
 $sql2['compte']--;
 echo $sql2['compte'].' id '.$sql2['id'].' '.$sql2['pseudo'].' <br />';
 if($sql2['compte'] != 0)
 {
  mysql_query("DELETE FROM pub WHERE pseudo = '".$sql2['pseudo']."' AND camp = '".$sql2['camp']."' LIMIT ".($sql2['compte']-1).")";
 }
}
echo 'opération effectuée';
?>

par Cyrano » 17 mai 2008, 18:43

celle donnée par rami est fausse (manque des AS pour le nom des tables).
Ce n'est pas obligatoire de le mettre, donc ça ne respecte pas de façon stricte le standard, mais c'est valide quand même avec MySQL.
Mais j'ai pas testé ce code. J'ai surtout essayé de le faire en une seule fois …
Et ça n'aurait pas marché : le COMMIT indique que tu tentes une transaction ... sans le début de la transaction, et surtout avec une table MyISAM.

par cicom » 17 mai 2008, 17:02

Merci HyWaN d'avoir cherché avec moi pendant un petit bout de temps...
Sinon j'ai trouvé une solution hyper lourde mais qui passe en plusieurs exécutions, ça consiste à tout supprimer et à réenregistrer une seule fois.
Voici le code.
<?php
include ('gs_includes/scripts.php');
$sql1 = mysql_query("SELECT count(t1.id) AS compte, t1.camp, t1.pseudo, t1.id FROM pub AS t1 INNER JOIN pub AS t2 ON ( t1.pseudo = t2.pseudo AND t1.camp = t2.camp AND t1.id <> t2.id ) WHERE t1.camp = '227' GROUP BY pseudo HAVING (compte > 1)") or die(mysql_error());
while($sql2 = mysql_fetch_array($sql1, MYSQL_ASSOC))
{
 $sql2['compte']--;
 echo $sql2['compte'].' id '.$sql2['id'].' '.$sql2['pseudo'].' <br />';
 if($sql2['compte'] != 0)
 {
  mysql_query("DELETE FROM pub WHERE pseudo = '".$sql2['pseudo']."' AND camp = '".$sql2['camp']."'");
  mysql_query("INSERT INTO pub VALUES('','".$sql2['camp']."','".$sql2['pseudo']."')");
 }
}
echo 'opération effectuée';
?>
Mais si certains ont une meilleure solution (plus légère surtout) je suis preneur, sinon je mettrais résolu d'ici à quelques jours...
Merci à tous!

par Hywan » 17 mai 2008, 16:15

Bon voici mes tests, mais je bloque.
On commence par faire notre table de test, et on y insère nos données :

Code : Tout sélectionner

CREATE TABLE IF NOT EXISTS `ma_table` ( `id` int(11) NOT NULL auto_increment COMMENT 'Identifiant.', `champ` varchar(255) NOT NULL COMMENT 'Champ au pif.', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ; INSERT INTO `ma_table` (`id`, `champ`) VALUES (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f'), (7, 'a'), (8, 'd'), (9, 'a');
Voici mes tests :

Code : Tout sélectionner

mysql> SHOW TABLES; +----------------+ | Tables_in_test | +----------------+ | ma_table | +----------------+ 1 row in set (0.00 sec)
J'ai tout d'abord sélectionner tous les champs avec leur nombre d'apparition. On doit voir apparaître a et d qui apparaissent respectivement 3 et 2. C'est facile, mais c'est pas intéressant. Ce qu'on veut, c'est avoir tous les a et les d listés avec leur id. On aurait alors :

Code : Tout sélectionner

mysql> SELECT a.id, a.champ -> FROM ma_table AS a, -> (SELECT champ, COUNT(champ) -> FROM ma_table -> GROUP BY champ -> HAVING COUNT(champ) > 1) AS b -> WHERE a.champ = b.champ; +----+-------+ | id | champ | +----+-------+ | 1 | a | | 4 | d | | 7 | a | | 8 | d | | 9 | a | +----+-------+ 5 rows in set (0.00 sec)
C'est pas très optimisé. J'ai amélioré la charge mémoire en faisant :

Code : Tout sélectionner

mysql> SELECT DISTINCT * -> FROM ma_table AS a -> WHERE EXISTS (SELECT * -> FROM ma_table AS b -> WHERE a.id <> b.id -> AND a.champ = b.champ); +----+-------+ | id | champ | +----+-------+ | 1 | a | | 4 | d | | 7 | a | | 8 | d | | 9 | a | +----+-------+ 5 rows in set (0.00 sec)
Bien, on a les champs, mais c'est pas encore ce qu'on veut exactement. Quand on a plusieurs fois la même valeur, on veut en conserver une. J'ai pris le choix de conserver la dernière entrée et pas la première. On aurait alors :

Code : Tout sélectionner

mysql> SELECT id, champ -> FROM ma_table AS a -> WHERE a.id < ANY (SELECT id -> FROM ma_table AS b -> WHERE a.id <> b.id -> AND a.champ = b.champ); +----+-------+ | id | champ | +----+-------+ | 1 | a | | 4 | d | | 7 | a | +----+-------+ 3 rows in set (0.00 sec)
Bien, c'est ça.
Maintenant, il faut supprimer. J'ai essayé 10 façons différentes, j'ai toujours la même erreur. J'ai essayé avec ou sans ANY, avec des EXISTS, des IN, des divisions etc., j'ai toujours une erreur avec le DELETE. Alors bon, je vous soumets ce que j'ai fais, si quelqu'un peut aller plus loin, ce sera bien :).

On peut le faire sinon en modifiant la table : soit en modifie les valeurs de champ, soit on crée un nouvel attribut. Mais j'aime pas trop cette méthode, je ne l'ai pas exploré plus que ça.

Sinon, on peut le faire en plusieurs requêtes. On aurait quelque chose du genre :

Code : Tout sélectionner

CREATE TABLE temp_table FROM (SELECT id, champ FROM ma_table GROUP BY champ); DELETE FROM ma_table; INSERT INTO ma_table SELECT * FROM temp_table; COMMIT; DROP TABLE temp_table;
Mais j'ai pas testé ce code. J'ai surtout essayé de le faire en une seule fois …

Wala Monsieur, en espérant que ça avancer un peu les choses.

par cicom » 17 mai 2008, 12:54

salut,
Les codes de vérification sont aussi dans ce scripts.
<?php
include ('gs_includes/scripts.php');
$sql1 = mysql_query("SELECT count(t1.id) AS compte, t1.camp, t1.pseudo, t1.id FROM pub t1 JOIN pub t2 ON ( t1.pseudo = t2.pseudo AND t1.camp = t2.camp AND t1.id <> t2.id ) WHERE t1.camp = '227' GROUP BY pseudo HAVING (compte > 1)") or die(mysql_error());
while($sql2 = mysql_fetch_array($sql1, MYSQL_ASSOC))
{
 $sql2['compte']--;
 echo $sql2['compte'].' id '.$sql2['id'].' '.$sql2['pseudo'].' <br />';
 if($sql2['compte'] != 0)
 {
  mysql_query("DELETE FROM pub WHERE pseudo = '".$sql2['pseudo']."' AND camp = '".$sql2['camp']."' LIMIT ".$sql2['compte']."");
 }
}
echo 'opération effectuée';
?>
Merci!