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 Re : Général » Contrainte d'unicité » 28/04/2023 18:41:53

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.

#2 Re : Général » Contrainte d'unicité » 28/04/2023 14:12:08

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.

#3 Re : Général » Contrainte d'unicité » 27/04/2023 22:22:46

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.

#4 Re : Général » Contrainte d'unicité » 27/04/2023 13:33:37

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.

#5 Général » Contrainte d'unicité » 27/04/2023 03:52:38

Jean-Marc68
Réponses : 8

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;

#6 Re : PL/pgSQL » Création d'une fonction de tri » 21/02/2021 16:06:25

Merci. Ce lien m'a échappé mais j'avais trouvé de l'info ici avec pas mal de codes d'options : http://unicode.org/reports/tr35/tr35-co … ng_Options (au cas où ça intéresserait qqn)

#7 Re : PL/pgSQL » Création d'une fonction de tri » 21/02/2021 06:19:34

Ça y est.
J'ai trouvé un collate numeric dans la doc

CREATE COLLATION numeric (provider = icu, locale = 'en-u-kn-true');

Selon ce que j'ai trouvé, je crois avoir compris que les nombres sont triés comme des nombres et pas comme de l'alphanumérique par l'option kn à true. Mais j'admets ne pas avoir encore compris le en-u. Le en serait l'anglais (pour le point comme séparateur décimal et la virgule comme séparateur de milliers je suppose), mais le u, je ne comprend pas.
En tout cas ça fonctionne.
Merci beaucoup de votre aide.

#8 Re : PL/pgSQL » Création d'une fonction de tri » 21/02/2021 00:02:17

Merci de votre réponse.
Mais quand j'essaye

select * from _test ORDER BY regexp_replace(val, '-([a-zA-Z])', '\1') COLLATE numeric;

dans ma bdd, j'obtiens l'erreur

ERROR: ERREUR:  le collationnement « numeric » pour l'encodage « UTF8 » n'existe pas
LINE 2: ORDER by regexp_replace(val, '-([a-zA-Z])', '\1') COLLATE nu...
                                                          ^


SQL state: 42704
Character: 71

(Ma base de donnée est en UTF-8 French_Canada.1252, et le postgresql.conf contient lc_numeric = 'French_Canada.1252')
Et sans le COLLATE numeric, je n'ai pas le bon résultat, ce qui est logique puisqu'il trie les nombres en alphanumérique (remarquez le 256-1-1) :

1-1-1
1A-2-2
1-A-2-3
256-1-1
50-1
50A-1-2
50-A-3-4
BL-1
BL1-1

Je crois comme vous que si je pouvais avoir un collate qui me permettre de trier en numérique ça règlerait mon problème.

#9 Re : PL/pgSQL » Création d'une fonction de tri » 20/02/2021 16:02:38

rjuju, sans doute me suis-je mal exprimé. Néanmoins, merci de vous attarder sur ma difficulté.
Je vais tenter de réexpliquer pour être plus clair.
Dans une colonne, j'ai des données qui sont exactes. Il est en effet possible d'avoir BL1, BL1-1, 50-1, 50A-1-2 et 50-A-3-4, 256-1-1.
Toutefois, lors d'un tri classique, il sortira dans l'ordre :
256-1-1
50-1
50-A-3-4
50A-1-2
BL1
BL1-1

Or il devrait sortir
50-1
50A-1-2
50-A-3-4
256-1-1
BL1
BL1-1

En fait ce sont des lots de terrains. Prenons le 256-1-1 en exemple. 256 est le lot de départ. Il a été divisé au min en 2 (256-1-1 et 256-1-2), puis la première partie a été divisée (admettons en 3 pour former 256-1-1, 256-1-2 et 256-1-1-3).
Jusque là la fonction naturalsort(text) que j'ai trouvée et donnée plus haut fonctionne bien. Même avec du 50-1-1 et du 50A-1-1 (50 et 50A ne sont pas le même lot. 50 et 50A ont été divisés tous les 2. C'est pour ça qu'on trouve 50-1-1 et 50A-1-2)
Malheureusement au cours des années certains ont écrit 50A et d'autres 50-A et le gouvernement les a acceptés comme tel. Il n'aurait pas fallu, mais je dois vivre avec. Je dois donc traiter 50A-1-2 et 50-A-3-4 qui sont en fait tous les 2 à considérer comme du 50A, mais pour le tri uniquement. Le lot dans la table doit impérativement rester avec son tiret.
Donc en fait, puisqu'il n'y a des lettres qu'au niveau supérieur, pour le tri on peut retirer le tiret qui précède une lettre (comme vous l'aviez suggéré). Puis trier par niveau.
Enfin, je voudrais pouvoir indexer la table sur ce champs et dans cet ordre. Parce que c'est la clé de recherche la plus souvent utilisée.

J'espère avoir été plus clair.
Et encore merci de votre aide qui m'es précieuse.

#10 Re : PL/pgSQL » Création d'une fonction de tri » 19/02/2021 21:22:37

rjuju a écrit :

Il n'est pas compliqué de supprimer le tiret s'il est suivi d'une lettre dans le tri, il suffit d'utiliser une clause telle que :

SELECT ...
FROM ...
ORDER BY regexp_replace(lacolonne, '-([a-zA-Z])', '\1')

et dans votre cas j'imagine en ajoutant une clause COLLATE pour prendre en compte un tri différent.

Merci de ton aide.
N'arrivant pas à modifier directement le regex pour tenir compte de ton conseil, J'ai modifié le regexp_matches comme ceci :

regexp_matches(regexp_replace($1, '-([a-zA-Z])', '\1'), '0*([0-9]+)|([^0-9]+)', 'g')

Bon, d'accord, je pense que ce n'est pas le regex le plus propre qui soit. Et sans doute est-ce plus lent qu'un regex correctement écrit parce qu'il me semble que que comme je j'ai écrit il y a une "couche" en plus (Il fait un regex de remplacement puis le regex de sélection au lieu de tout faire en une fois dans le regex).
Je crois qu'il doit y avoir moyen de "supprimer" le tiret qui est avant la lettre directement dans le regex (pas dans la première partie du match, comme je l'ai fait), mais je ne trouve pas la solution.
En tout cas il me semble qu'il fonctionne comme je l'ai écrit (du moins il fonctionne avec les tests que j'ai faits).
Quant au COLLATE, je ne connaissais pas, mais si j'ai bien compris ce que j'ai lu, ce serait pour la gestion des caractères accentués (UTF-8 p.ex). Or dans mon cas je n'en ai pas besoin. Ce sont (normalement) seulement des lettres majuscules de A à F (mais je garde quand-même le [a-zA-Z] au cas où une ligne aurait été mal encodée (il faut vivre avec l'existant).

#11 Re : PL/pgSQL » Création d'une fonction de tri » 19/02/2021 18:59:38

Merci de ton aide rjuju.
C'est vrai que c'est une bonne idée.
Par contre je ne peux pas indexer avec ça, or j'ai quand-même pas mal de lignes et le tri ne se fait que sur cette mode, donc je pensais l'indexer comme ça.

J'avais trouvé cette fonction qui me permet d'indexer ma table en tri naturel, et j'espérais pouvoir modifier le regex pour qu'il ne tienne pas compte du tiret précédent une lettre, mais mes connaissances sont trop limitées et dans mes essais je bousille le regex au lien de l'améliorer pour mon besoin.

CREATE OR REPLACE FUNCTION public.naturalsort(text)
    RETURNS bytea
    LANGUAGE 'sql'
    COST 100
    IMMUTABLE STRICT PARALLEL UNSAFE
AS $BODY$
select string_agg(
		convert_to(
			coalesce(
				r[2],
				length(length(r[1])::text) || length(r[1])::text || r[1])
			,'SQL_ASCII')
		,'\x00')
    from regexp_matches($1, '0*([0-9]+)|([^0-9]+)', 'g') r;
$BODY$;

#12 PL/pgSQL » Création d'une fonction de tri » 19/02/2021 16:19:52

Jean-Marc68
Réponses : 10

Bonjour,
Je ne suis pas un grand habitué des regex, aussi je fais appel à vos connaissances.
J'ai trouvé la fonction naturalsort qui permet le tri naturel.
Mais j'ai besoin d'un tri un peu différent.

Résultat recherché :
1-84
1-84-1
1-84-2
1-85
1A-4
1A-30-2
1-F-2-3
1-F-12
1-F-13-1

Logique : les tirets représentent des "étages". Donc le 1 contient le 1-1, le 1-2, qui lui contient le 1-2-1, le 1-2-2, ...
              Là où se trouve ma difficulté c'est qu'au premier niveau il y a parfois des lettres. Exemple 1A, 2C, ... mais aussi des lettres avec des tirets devant (et on ne peut pas les changer. C'est effectivement comme ça et je dois vivre avec).
Donc quand un tiret précède une lettre, il ne faut pas en tenir compte dans le tri. Pour le tri, 12-F devrait être considéré comme 12F, mais pour le tri uniquement. Remarque : les lettres existent seulement au 1er supérieur.
J'ai vraiment besoin d'aide pour ce tri parce que j'ai beau essayer, je ne m'en sors pas.

Merci de vos z'avis z'avisés.

#13 Re : .NET » Problème d'affichage d'erreurs » 19/02/2021 16:01:02

Merci rjuju.
En continuant mes recherches j'ai vu aussi que je devais faire ces changements. J'ai donc modifié NpgsqlException pour PostgresException et NpgsqlEx.Code pour NpgsqlEx.SqlState, mais j'ai toujours le pbl de ne rien comprendre à l'erreur qui sort.

#14 .NET » Problème d'affichage d'erreurs » 16/02/2021 20:51:33

Jean-Marc68
Réponses : 3

Bonjour,

J'ai fini par migrer de version majeure. Je le fais le moins possible parce que ça engendre souvent des pbl, mais à un moment il faut se mettre un peu à jour, et évidemment j'ai un pbl avec une vieille application. Elle était développée avec un npgsql v 2.XX qui n'est plus supportée (l'application refuse de se connecter à la BDD alors que toutes les autres se connectent correctement vu que l'adresse IP et le port sont restés les mêmes). J'ai donc installé le nuget de npgsql 5.0.3 et passé le framework de 4.5 à 4.7.2 (sinon le nuget ne s'installait pas).
J'ai fais qq modifs nécessaires au changement de version du npgsql, mais il me reste 2 pbl.

1. J'avais

catch (NpgsqlException NpgsqlEx)
                        {
                            if (NpgsqlEx.Code == "23505")
                             {

    Mais il ne veut plus du NpgsqlEx.Code. Je peux admettre avoir mal cherché, mais je n'ai pas trouvé l'info. Comment dois-je faire pour récupérer le code de l'erreur ?

2. Lorsque je roule le Debug et qu'une erreur est levée, Les infos sont écrites en caractères asiatiques (chinois, japonais, ... en tout cas qqch que je ne comprend pas.
    exemple d'erreur retournée :
    Code : 㠰ぐ?
    Message : 㩤灜楧獮慴汬牥ㅟ⸳畡潴灜獯杴敲⹳楷摮睯⵳㙸尴牳屣慢正湥層潰瑳慭瑳牥灜獯浴獡整⹲?

Merci d'avance de votre aide qui m'est toujours précieuse.

#15 Re : .NET » select sur une vue via npgsql » 29/08/2019 21:10:53

Arf. Évidemment.
Voilà ce qui arrive quand on a le C# avec sa normalisation de noms de variables sur un écran et PostgreSQL avec une autre normalisation sur l'autre écran.
Je vais renommer les vues avec une casse pour respecter la normalisation PostgreSQL.
Merci de m'avoir fait remarquer ce que j'avais collé devant le nez et que je ne voyais pas.

#16 .NET » select sur une vue via npgsql » 29/08/2019 15:50:10

Jean-Marc68
Réponses : 2

Salut,

Je code en C# et je me lie à postgresql via npgsql (à jour, version 4.0.9).

Je n'ai aucun problème à accéder aux tables, mais lorsque je crée une vue et que je veux la lire, je reçois un message d'erreur me disant que la table n'existe pas (erreur 42P01)

Voici une vue dans postgresql

CREATE OR REPLACE VIEW public."OCTRencodees" AS 
 SELECT documents.num_document_cadastre AS no_octr,
    documents.minute,
    documents.date_minute,
    documents.ag,
    documents.matricule_ag
   FROM documents
  WHERE documents.type_document::text = 'OCTR'::text
  GROUP BY documents.num_document_cadastre, documents.minute, documents.date_minute, documents.ag, documents.matricule_ag
  ORDER BY documents.num_document_cadastre;

ALTER TABLE public."OCTRencodees"
  OWNER TO jmdeneyer;
COMMENT ON VIEW public."OCTRencodees"
  IS 'Donne la liste des OCTR encodées';

Voici le code de lecture de cette vue

public static MTObservableCollection<MinuteDocument> ListeOCTRencodés()
        {
            NpgsqlConnection conn = new NpgsqlConnection(Properties.Settings.Default.PostGISconnexionString);
            MTObservableCollection<MinuteDocument> listeOCTR = new MTObservableCollection<MinuteDocument>();
            string listeOCTRencodéssql = @"SELECT * FROM OCTRencodees;";
            NpgsqlCommand listeOCTRencodéscommand = new NpgsqlCommand(listeOCTRencodéssql, conn);
            NpgsqlDataReader listeOCTRencodésdr;

            try
            {
                conn.Open();
                using (listeOCTRencodésdr = listeOCTRencodéscommand.ExecuteReader())
                {
                    while (listeOCTRencodésdr.Read())
                    {
                        MinuteDocument octr = new MinuteDocument();
                        int noMandat = 0, noMatricule = 0;
                        DateTime dateMinute = new DateTime();
                        if (int.TryParse(listeOCTRencodésdr["no_octr"].ToString(), out noMandat))
                            octr.Numero = noMandat;
                        if (int.TryParse(listeOCTRencodésdr["matricule_ag"].ToString(), out noMatricule))
                            octr.Matricule = noMatricule;
                        if (DateTime.TryParse(listeOCTRencodésdr["date_minute"].ToString(), out dateMinute))
                            octr.DateMinute = dateMinute;
                        octr.Minute = listeOCTRencodésdr["minute"].ToString();
                        octr.AG = listeOCTRencodésdr["ag"].ToString();
                        listeOCTR.Add(octr);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("la lecture des OCTR encodées a engendré l'erreur suivante.Message : " + ex.Message, ex);
    }
            finally
            {
                conn.Close();
            }
            if (listeOCTR.Count > 0)
                return listeOCTR;
            return null;
        }

Voici le message que je reçois

System.Exception
  HResult=0x80131500
  Message=la lecture des OCTR encodées a engendré l'erreur suivante.Message : ERREUR: 42P01: la relation « octrencodees » n'existe pas
  Source=TopocomArchives
Exception interne 1 :
NpgsqlException : ERREUR: 42P01: la relation « octrencodees » n'existe pas

Qu'est-ce que je fais mal ?
Que dois-je faire pour avoir accès aux vues ?
Merci de vos z'avis z'avisés.

#17 Re : PL/pgSQL » SQL pour itération de fonction avec le contenu d'un champs en argument » 23/08/2019 19:21:57

Je pensais qu'il y avait moyen de le faire sans passer par une autre fonction.
Je vais essayer cela.

Merci.

#18 PL/pgSQL » SQL pour itération de fonction avec le contenu d'un champs en argument » 23/08/2019 15:17:28

Jean-Marc68
Réponses : 7

Salut,

J'ai fais une fonction update "desactiver_couverts(numero_document integer)" qui prend un nombre en argument.
Maintenant que ma fonction fonctionne, je dois la faire fonctionner avec tous les nombres (dans l'ordre croissant de ces nombres, c'est important) contenus dans une colonne.
Le problème est que je ne sais pas (et je n'arrive pas en fonction de ce que j'ai trouvé) à faire l'itération qui va me permettre de rouler la fonction avec les nombres de la colonne en ordre ascendant.

Quelqu'un aurait-il un exemple de SQL à me montrer qui reprendrait un champs pour alimenter une fonction ?

Merci de vos z'avis z'avisés.

Pied de page des forums

Propulsé par FluxBB