Page 1 sur 2

Query failed: ERROR: duplicate key violates unique constrain

Posté : 13 août 2007, 10:24
par laeti
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.

Posté : 13 août 2007, 10:42
par Ryle
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.

Posté : 13 août 2007, 10:44
par zeus
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

Posté : 13 août 2007, 10:45
par laeti
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.

Posté : 13 août 2007, 10:45
par d0m
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.

Posté : 13 août 2007, 10:46
par laeti
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()); 

Posté : 13 août 2007, 10:46
par zeus
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());
        } 

Posté : 13 août 2007, 10:50
par Ryle
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

Posté : 13 août 2007, 10:51
par laeti
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?

Posté : 13 août 2007, 10:55
par d0m
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.

Posté : 13 août 2007, 11:09
par laeti
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')

Posté : 13 août 2007, 11:15
par d0m
tu n'aurais pas dans ta table referentiel_spatial le champ ref_spa_nom contenu dans la clé primaire?

Posté : 13 août 2007, 11:35
par Genova
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.

Posté : 13 août 2007, 11:49
par Sékiltoyai
Non, Genova, dans PostgreSQL, il y a aussi un champ qui se comporte comme le champ autoincrement. C'est le type de champ SERIAL.

Posté : 13 août 2007, 11:52
par Genova
Ah, mes excuses alors, c'est bon à savoir :)