Query failed: ERROR: duplicate key violates unique constraint

Eléphant du PHP | 91 Messages

13 août 2007, 10:24

Bonjour,

Dans un formulaire, j'ai une liste déroulante qui m'affiche des données d'une table de ma base postgres puis un champs texte pour ajouter un libellé dans cette même table.
Voici donc le code correspond:

Formulaire:
Quel(s) référentiel(s) spatial(aux) est/sont utilisé(s)? :          
		Autre:    
		<input id="Ref_spa_autre" name="Ref_spa_autre" size="40" type="text"><BR>
		<select id="Ref_spa" name="Ref_spa[]" size="5" multiple="multiple"><option value="">-- Saisissez un/des référentiel(s) spatial(aux) --</option>
				<!--Intégration des référentiels spatiaux de la base de données dans la liste déroulante --->
				<?php
						// requête sql
						$sql = "SELECT DISTINCT ref_spa_nom, ref_spa_id FROM referentiel_spatial ORDER BY ref_spa_nom asc";
	
						// on sélectionne toutes les entrées libellés des référentiels spatiaux de la table ref_spa
						$req=pg_query($sql) or die('Erreur SQL !'.$sql.'<br>'.pg_resul_error());
						
						//On affiche ces entrées dans la liste déroulante 
						while ($line=pg_fetch_array($req))
						{
							echo "<option name='Ref_spa' value=\"".$line['ref_spa_id']."\">".$line['ref_spa_nom']."</option>";
						}
				?>
		</select>
Traitement:
// On prépare la requête pour insérer les identifiants dans la table str_ref_spa et on exécute cette requête
		for ($i=0; isset($_POST['Ref_spa'][$i]); $i++) {
			$sql = "INSERT INTO str_ref_spa(ref_spa_id, str_id) VALUES (".$_POST['Ref_spa'][$i].",".$str_id.")";
			$req = pg_query($sql) or die('Erreur SQL !'.$sql.'<br>'.pg_result_error());
		}
		
		// On teste si un libellé est saisi et on compte le nombre d'entrées dans la table ref_spa qui contient $Ref_spa_autre comme valeur
		if ($Ref_spa_autre!= "" or $Ref_spa_autre!=null){
			$sql = "SELECT count(*) AS nb FROM referentiel_spatial WHERE ref_spa_nom='".$Ref_spa_autre."'";
			$req = pg_query($sql) or die('Erreur SQL !'.$sql.'<br>'.pg_result_error());
			$resul=pg_fetch_assoc($req);
				// On vérifie si le libellé du référentiel spatail existe déjà dans la base de données
				if ($resul['nb']==0){
				// On prépare la requête pour insérer le libellé du reseau_sig de type autre saisi dans la textarea et on exécute cette requête
				[size=150]$sql = "INSERT INTO referentiel_spatial(ref_spa_nom) VALUES ('".$Ref_spa_autre."')";
				$req = pg_query($sql) or die('Erreur SQL !'.$sql.'<br>'.pg_result_error());[/size]
				}
					// On prépare la requête pour récupérer l'identifiant de ce nouveau référentiel spatial et on exécute cette requête
					$sql = "SELECT ref_spa_id FROM referentiel_spatial WHERE ref_spa_nom='".$Ref_spa_autre."'";
					$req = pg_query($sql) or die('Erreur SQL !'.$sql.'<br>'.pg_result_error());
					$resul_ref_spa_id = pg_fetch_assoc($req);
						// On prépare la requête pour insérer l'identifiant dans la table str_ref_spa et on exécute cette requête
						$sql = "INSERT INTO str_ref_spa(ref_spa_id, str_id) VALUES (".$resul_ref_spa_id['ref_spa_id'].",".$str_id.")";
						$req = pg_query($sql) or die('Erreur SQL !'.$sql.'<br>'.pg_result_error());
		}
J'ai déjà eu ce genre de démarche et je n'avais pas eu de pbs dans mon souvenir mais là, j'ai un pb au niveau de l'insertion du nouveau libellé dans ma table qui contient déjà des enregistrements. J'espère avoir été claire et que quelqu'un peut m'aider.
Merci.

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

13 août 2007, 10:42

D'après le message d'erreur, ton problème vient du fait que tu essayes d'insérer une valeur qui existe déjà dans une colonne avec une contrainte d'unicité....

Affiche ta requête, regarde la valeur que tu essayes d'insérer, regarde si elle est déjà en base et pis... ben agit en conséquence ;) La précédente valeur est-elle en base parce que tu viens de l'y insérer ? tu peux peut être tester pour ne pas l'insérer deux fois; est-elle déjà en base avant le traitement ? tu peux t'en assurer avant de jouer l'insert ou faire un "insert or update"; Etc.
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

13 août 2007, 10:44

L'erreur que tu nous indiques est associée à quelle requête ?

J'ai l'intuition qu'il s'agit de la 1ere requête puisque tu spécifies l'id à insérer ... :-k
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Eléphant du PHP | 91 Messages

13 août 2007, 10:45

Mon nouveau libellé n'existe pas dans ma base. J'ai d'ailleurs fait un test pour vérifier si il existe avant de l'insérer et ça, ça marche très bien.

d0m
Mammouth du PHP | 1141 Messages

13 août 2007, 10:45

Le message d'erreur est explicite :
Dans ta table les identifiants sont uniques et tu essaies d'insérer un élement avec identifiant qui existe déjà.

Si les identifiants sont déclarés comme 'auto-increment' alors il ne faut pas préciser l'identifiant quand tu insères l'élement. Sinon il faut en calculer un nouveau toi même.

Eléphant du PHP | 91 Messages

13 août 2007, 10:46

Il s'agit de cette requête là:
 // On prépare la requête pour insérer le libellé du reseau_sig de type autre saisi dans la textarea et on exécute cette requête
               $sql = "INSERT INTO referentiel_spatial(ref_spa_nom) VALUES ('".$Ref_spa_autre."')";
                $req = pg_query($sql) or die('Erreur SQL !'.$sql.'<br>'.pg_result_error()); 

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

13 août 2007, 10:46

Dans ce bout de code, tu ne testes pas la présence de l'identifiant de la base ... ;)
// On prépare la requête pour insérer les identifiants dans la table str_ref_spa et on exécute cette requête
        for ($i=0; isset($_POST['Ref_spa'][$i]); $i++) {
            $sql = "INSERT INTO str_ref_spa(ref_spa_id, str_id) VALUES (".$_POST['Ref_spa'][$i].",".$str_id.")";
            $req = pg_query($sql) or die('Erreur SQL !'.$sql.'<br>'.pg_result_error());
        } 
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

13 août 2007, 10:50

Pis y a aussi un truc qui me chiffone... quand tu fais l'insertion uniquement du libellé, ça sous entends que c'est ta base qui va faire un auto-increment pour déterminer l'id à associer ?

Si par ailleurs tu spécifies toi même des id à insérer (cf. la requête pointée par zeus), il se peut qu'il y ait un décallage entre tes ids en bases et la valeur d'auto incrementation de la table.. du coup il risque d'utiliser des ids qui ont déjà été distribués ? ... :-k
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Eléphant du PHP | 91 Messages

13 août 2007, 10:51

En effet, d0m, il s'agit bien d'un id auto-incrément. Donc si je te suis bien quand je vais mon insert, il commence à 1, or comme ma table contient déjà des éléments le 1 existe déjà. Comment dois-je recalculer tout ça pour recommencer à 24 par exemple?

d0m
Mammouth du PHP | 1141 Messages

13 août 2007, 10:55

en auto increment tu n'as pas besoin de gérer les identifiants, ils sont incrémentés automatiquement.
Quand tu veux insérer un élément, tu le fais comme ceci :
"INSERT INTO str_ref_spa(str_id) VALUES (".$str_id.")"; 
L'identifiant s'incrémentera à chaque insertion et chaque élement aura un identifiant différents aux autres.

Eléphant du PHP | 91 Messages

13 août 2007, 11:09

C'est bien ce que j'ai fait. J'ai peut-être mis un peu trop de code, ça a donc peut-être embrouillé tout le monde.

La requête qui me pose pb est la suivante:
$sql = "INSERT INTO referentiel_spatial(ref_spa_nom) VALUES ('".$Ref_spa_autre."')";
				$req = pg_query($sql) or die('Erreur SQL !'.$sql.'<br>'.pg_result_error());
et le message d'erreur complet est le suivant:

Warning: pg_query() [function.pg-query]: Query failed: ERROR: duplicate key violates unique constraint "referentiel_spatial_pkey" in C:\Program Files\wamp\www\Site_enquete\traitement_saisie3.php on line 58
Erreur SQL !INSERT INTO referentiel_spatial(ref_spa_nom) VALUES ('bd geo')

d0m
Mammouth du PHP | 1141 Messages

13 août 2007, 11:15

tu n'aurais pas dans ta table referentiel_spatial le champ ref_spa_nom contenu dans la clé primaire?

ViPHP
ViPHP | 928 Messages

13 août 2007, 11:35

en auto increment tu n'as pas besoin de gérer les identifiants, ils sont incrémentés automatiquement.
Quand tu veux insérer un élément, tu le fais comme ceci :
"INSERT INTO str_ref_spa(str_id) VALUES (".$str_id.")"; 
L'identifiant s'incrémentera à chaque insertion et chaque élement aura un identifiant différents aux autres.
Attention, ceci n'est pas valable en PostGreSQL. Il semble que laeti utilise justement une base de donnée PostGreSQL et non du MySQL. En Pgsql si je me rappel bien la gestion des auto increment est à faire via une séquence

Code : Tout sélectionner

CREATE SEQUENCE ma_seq; SELECT SETVAL('ma_seq', (SELECT CASE WHEN MAX(mon_champ) > 0 THEN MAX(mon_champ)+1 ELSE 1 END FROM ma_table));
et dans la déclaration du champ dans le CREATE TABLE :

Code : Tout sélectionner

mon_champ INT DEFAULT nextval('ma_seq')
Vérifie donc si tu as bien fait ça si tu as voulu créer une clef primaire qui s'auto incrémente.

ViPHP
ViPHP | 5924 Messages

13 août 2007, 11:49

Non, Genova, dans PostgreSQL, il y a aussi un champ qui se comporte comme le champ autoincrement. C'est le type de champ SERIAL.

ViPHP
ViPHP | 928 Messages

13 août 2007, 11:52

Ah, mes excuses alors, c'est bon à savoir :)