PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 27/04/2023 03:52:38

Jean-Marc68
Membre

Contrainte d'unicité

Bonjour,
Je viens de me rendre compte qu'une contrainte d'unicité que j'avais établie pour une table ne fonctionne pas (ou plutôt j'imagine que j'ai dû mal la faire).
Je m'en suis rendu compte parce que j'ai créé par erreur un anc_lot qui existait déjà (sauf pour le id_anc_lot et le code_circ qui étaient différents mais vu la contrainte code_cad_code_ds_no_lot_key selon moi ça n'aurait pas dû passer) et c'est passé.

Qu'est-ce que j'ai mal fait (et donc comment dois-je le corriger ?)
Merci.


Le SQL de ma table est :
-- Table: greffe.anc_lots

-- DROP TABLE greffe.anc_lots;

CREATE TABLE greffe.anc_lots
(
    id_anc_lot integer NOT NULL DEFAULT nextval('greffe.anc_lots_id_seq'::regclass),
    code_circ smallint NOT NULL,
    code_cad integer NOT NULL,
    code_ds character varying(255) COLLATE pg_catalog."default" NOT NULL,
    no_lot character varying(255) COLLATE public."numeric" NOT NULL,
    CONSTRAINT anc_lots_pkey PRIMARY KEY (id_anc_lot),
    CONSTRAINT code_cad_code_ds_no_lot_key UNIQUE (code_cad, code_ds, no_lot)
)

TABLESPACE pg_default;

ALTER TABLE greffe.anc_lots
    OWNER to jm;

GRANT DELETE, INSERT, SELECT, UPDATE ON TABLE greffe.anc_lots TO application_greffe;

GRANT ALL ON TABLE greffe.anc_lots TO jm;
-- Index: anc_lots_code_cad_idx

-- DROP INDEX greffe.anc_lots_code_cad_idx;

CREATE INDEX anc_lots_code_cad_idx
    ON greffe.anc_lots USING btree
    (code_cad ASC NULLS LAST)
    TABLESPACE pg_default;
-- Index: anc_lots_code_circ_idx

-- DROP INDEX greffe.anc_lots_code_circ_idx;

CREATE INDEX anc_lots_code_circ_idx
    ON greffe.anc_lots USING btree
    (code_circ ASC NULLS LAST)
    TABLESPACE pg_default;
-- Index: anc_lots_code_ds_idx

-- DROP INDEX greffe.anc_lots_code_ds_idx;

CREATE INDEX anc_lots_code_ds_idx
    ON greffe.anc_lots USING btree
    (code_ds COLLATE pg_catalog."default" ASC NULLS LAST)
    TABLESPACE pg_default;
-- Index: anc_lots_code_lot_idx

-- DROP INDEX greffe.anc_lots_code_lot_idx;

CREATE INDEX anc_lots_code_lot_idx
    ON greffe.anc_lots USING btree
    (no_lot COLLATE public."numeric" ASC NULLS LAST)
    TABLESPACE pg_default;

Hors ligne

#2 27/04/2023 09:42:17

rjuju
Administrateur

Re : Contrainte d'unicité

Bonjour,


Avez-vous une erreur si vous faites un REINDEX de cette table ?  C'est probablement un problème de mise à jour de glibc / ICU, cf https://wiki.postgresql.org/wiki/Locale_data_changes

Hors ligne

#3 27/04/2023 13:33:37

Jean-Marc68
Membre

Re : Contrainte d'unicité

Bonjour Julien,

Merci de votre attention et de votre proposition mais non, le réindex n'a donné aucune erreur :

REINDEX

Query returned successfully in 1 secs 161 msec.

Hors ligne

#4 27/04/2023 22:09:42

dverite
Membre

Re : Contrainte d'unicité

On voit que cette collation non standard intervient dans la contrainte unique:


no_lot character varying(255) COLLATE public."numeric" NOT NULL,

Quelle est la définition de cette collation?

Est-ce qu'une requête SELECT avec un GROUP BY sur les colonnes de la contrainte et HAVING count(*)>1 renvoie effectivement des lignes?

Hors ligne

#5 27/04/2023 22:22:46

Jean-Marc68
Membre

Re : Contrainte d'unicité

Bonjour dverite,
J'avais créé cette table avec PgAdmin4 et je n'ai pas remarqué ce collate (et honnêtement je ne sais pas ce que c'est ni à quoi ça sert).
Mon attention attirée, je constate qu'il y en a un sur le code_ds aussi, comme dans beaoucoup de colonnes d'autres tables que j'ai créées avec PgAdmin4.

Est-ce qu'une requête SELECT avec un GROUP BY sur les colonnes de la contrainte et HAVING count(*)>1 renvoie effectivement des lignes?

Dès que je me suis rendu compte qu'il prenait une ligne qu'il n'aurait pas du, j'ai fait la vérification et, une fois cette nouvelle ligne erronée supprimée, il n'y a pas de doublon dans la table.

Comment puis-je enlever ces collate en m'assurant de ne pas perdre de donnée ?
Merci de votre attention et de votre aide.

Dernière modification par Jean-Marc68 (27/04/2023 22:25:29)

Hors ligne

#6 28/04/2023 04:46:55

rjuju
Administrateur

Re : Contrainte d'unicité

Vous pouvez utiliser


ALTER TABLE nom_table ALTER COLUMN nom_colonne TYPE nom_type COLLATE "default";

Hors ligne

#7 28/04/2023 14:12:08

Jean-Marc68
Membre

Re : Contrainte d'unicité

Merci de l'info rjuju,

Toutefois quand j'ai posé la question j'étais à la maison (ça me travaille le soir), et arrivé au bureau, en faisant la correction que tu me donnes, je me suis demandé pourquoi cette colonne avait un collate différent des autres (ça ne pouvais pas être venu tout seul). En fouillant dans mes dossiers, j'ai retrouvé que j'ai mis ce collate pour avoir un tri "naturel". Mais vu que ça pose problème, je vais le laisser à défault (de toute manière je suis le seul à travailler dans postgresql. Les autres utilisateurs utilisent des applications qui font appel à PostgreSQL (il faudra "simplement" que je vérifie que les tris se fassent dans les applications et pas dans les appels sql)).

Merci beaucoup à vous deux.

Dernière modification par Jean-Marc68 (28/04/2023 15:04:05)

Hors ligne

#8 28/04/2023 18:01:15

dverite
Membre

Re : Contrainte d'unicité

La collation influe sur le résultat de la comparaison des chaînes de caractères.

Ici la contrainte d'unicité sur (code_cad, code_ds, no_lot) implique qu'à l'insertion ou MAJ d'une ligne, le moteur vérifie qu'il n'y a pas déjà une valeur pour laquelle il y aurait code_cad=nouveau code_cad ET code_ds=nouveau code ds ET no_lot=nouveau no_lot.


Comme il y a une collation personnalisée affectée à la colonne no_lot, la comparaison no_lot=nouveau no_lot se fait avec cette collation. Sans savoir comment est définie cette collation (ça peut se voir avec select * from pg_collation WHERE collname='numeric') et quelle est la valeur de no_lot qu'il ne reconnait pas comme un doublon alors que c'en serait un, difficile de dire si c'est la faute de la collation.


Surtout dans ce sens là d'ailleurs. Si c'était une valeur différente qui était égale d'après la collation, ce serait plus compréhensible (par exemple abc=ABC pour une collation case-insensitive). Mais deux valeurs réellement identiques à l'octet près dont la collation dit qu'elle sont différentes, là je ne vois pas bien quelle collation pourrait dirait ça. Une autre piste pourrait être plus simplement des caractères invisibles dans les valeurs, avec Unicode ça arrive. Dans ce cas, le fait qu'il y a une collation personnalisée serait une coïncidence.

Hors ligne

#9 28/04/2023 18:41:53

Jean-Marc68
Membre

Re : Contrainte d'unicité

Les valeurs de cette table proviennent d'une importation d'une ancienne table en Access et effectivement, il y avait bien un caractère en plus dans certaines lignes  valeur (je n'ai pas pensé à "trimmer" les champs et après vérification sur les champs code_ds et no_lot (qui sont des string) j'ai effectivement certains endroit où il y a un espace à la fin du champs. Heureusement après vérification il y a seulement 22 doublons dus à cet espace. Je vais donc d'abord régler les doublons (changer l'id dans les tables liées et enlever les lignes qui ont un espace), puis je vais faire une requete update pour supprimer les espaces.
Ça devrait résoudre mon problème.
Merci beaucoup.

Hors ligne

Pied de page des forums