mercredi 12 mars 2014

Tableau croisé dynamique avec des données postgresql

Dans le billet précédent, nous nous sommes efforcés de construire dans Libreoffice Calc un rapport du même genre que celui que nous avions obtenu dans Libreoffice Base. Mais Libreoffice Calc permet beaucoup plus. Nous allons ici construire à partir des mêmes données postgresql un tableau croisé dynamique (pour la définition de la table et de la vue utilisée, ainsi que pour les données: voir ce billet).

On commence par utiliser le menu Données => Table de Pilote => Créer:


Nous supposons que le fichier bdtest.odb permettant la connexion à postgresql existe et qu'il a été enregistré:


Nous sélectionnons la source de données opérationsv qui correspond à une vue définie au niveau de postgresql:


Dans la fenêtre qui surgit, il suffit de faire glisser ce qui convient là où ça convient:


"an" placé dans la zone "Champs de page" nous permettra de filtrer le tableau suivant l'année:


Il reste à formater convenablement les cellules et c'est terminé:


Plutôt que de placer "mois-n" et "mois" dans la zone "Champs de colonne", on pourrait y placer "date_exec". On arriverait alors à un tableau tel que celui-ci (dont nous n'affichons qu'une partie):

(Il faut mettre la ligne "contrepartie" au format date)

Ensuite appuyant sur F12 après avoir sélectionné une date, nous avons la possibilité de grouper par mois:


ce qui transforme radicalement le tableau:


En plaçant "crédit" et "débit" dans la zone "Champs de données", on aboutirait  à ceci:


En cas de changement de données au niveau de postgresql, il suffit de cliquer droit sur le tableau qui nous intéresse et dans le menu contextuel qui surgit, choisir "Actualiser".

mardi 11 mars 2014

Utilisation données postgresql dans lbo calc

Dans le cadre de ce blog, nous avons toujours parlé de connexion entre Libreoffice Base et une base de données postgresql. Ainsi par exemple suite à une connexion vers la base de données bdtest, il en est résulté un fichier bdtest.odb qui contient non seulement les paramètres de connexion


mais aussi tout ce qui a pu être créé (requêtes, formulaires, rapport).
Ainsi on peut y obtenir ce rapport basé sur les données figurant dans une table opérations:


(voir ce billet

Nous allons montrer ici comment utiliser Libreoffice Calc pour réaliser un rapport de ce genre.
Ouvrons Libreoffice Calc et appuyons sur F4 (EDIT: CTRL-MAJ-F4) pour afficher les sources de données:


Si bdtest.odb n'y figure pas, il faut l'ajouter via Outils=> Options => Libreoffice Base => Base de données=> Nouveau




Après que bdtest ait été référencé, nous pouvons y choisir comme source de données pour ce rapport la requête opérationsr (la même qui a été utilisée dans ce billet) et nous filtrons sur l'année 2013:



Ensuite nous trions suivant mois_n et référence:



Après avoir sélectionné l'ensemble des données, il reste à les insérer dans le tableau avec l'icône "Données dans le texte":



Ensuite passant par le menu Données => Sous-totaux:


nous avons la possibilité de calculer les sous-totaux pour chaque mois:


Dans l'onglet "Options", nous n'oublions pas de décocher la case "Trier" car d'une part les données ont déjà été triées, d'autre part le tri positionnerait par exemple "Février" avant "Janvier".
Le reste est du peaufinage:
  • nous formatons de manière adéquate les cellules numériques,
  • déplaçons la colonne "contrepartie" après la colonne "solde_c",
  • déplaçons la colonne "reference" après la colonne "mois",
  • supprimons les colonnes "an" et "seq" et masquons la colonne "mois_n".

Et voici le résultat:


Notons que pour déplacer une colonne, il faut la sélectionner (en cliquant sur l'en-tête) et ensuite procéder avec la souris tout en maintenant la touche 'Alt Gr' enfoncée. Pour la colonne "reference", il faut au préalable insérer une colonne vide avant la colonne "date_exec".

Nous pouvons aussi décider de masquer les détails:


(ne pas sélectionner les deux dernières lignes)


dimanche 5 janvier 2014

Postgresql upgrade 2

Dans l'article Postgresql upgrade, nous avons traité de la migration des données postgresql lors du passage de Fedora 19 à Fedora 20.
Cette fois, nous allons considérer le même problème pour une autre distribution, à l’occurrence "Chakra". Cependant le contenu de cet article pourrait être utilisé dans d'autres cas.

En tant qu'utilisateur postgres, sauvegardons les anciennes données sous un nom qui rappelle l'ancienne version de postgresql:

[toto@rigel ~]$ su -
Mot de passe : 
[root@rigel ~]# su - postgres
[postgres@rigel ~]$ mv /var/lib/postgres/data/ /var/lib/postgres/data_9.2/

Dans la foulée nous pouvons créer le nouveau cluster:

[postgres@rigel]$ initdb --locale fr_FR.utf8 -E UTF8 -D /var/lib/postgres/data

Notons que au démarrage de postgresql.service, il est prévu le lancement d'un script qui initialise la database si celle-ci ne l'est pas encore:

[toto@rigel ~]$ grep "ExecStartPre" /usr/lib/systemd/system/postgresql.service 
ExecStartPre=/usr/lib/systemd/scripts/postgresql-initdb

Donc pour coller au plus près de ce qui a été fait auparavant, nous aurions pu, au lieu d'utiliser la commande initdb, procéder comme ceci:

[root@rigel ~]# /usr/lib/systemd/scripts/postgresql-initdb

à condition d'avoir pris quelques précautions.
La commande suivante:

[toto@rigel ~]$ head -5 /usr/lib/systemd/scripts/postgresql-initdb
#!/bin/sh

set -e


. /etc/conf.d/postgresql

montre que le script utilise /etc/conf.d/postgresql.
L'examen de ce fichier nous conduit à devoir y remplacer, avant l'exécution du script,  en_US par ce qui convient:

[root@rigel ~]# sed -i 's/en_US/fr_FR/' /etc/conf.d/postgresql

Quelle que soit la méthode employée pour initialiser la database, il reste ensuite à utiliser  pg_upgrade pour procéder à la migration. Avec Fedora, pg_upgrade venait avec le paquet postgresql-upgrade qui fournissait également les commandes relatives à l'ancienne version de postgresql.
Rien de tel cette fois, pg-upgrade vient avec le paquet postgresql:

[toto@rigel ~]$ pacman -Qo $(which pg_upgrade)
/usr/bin/pg_upgrade appartient à postgresql 9.3.2-1

Interrogeons le paquet à la recherche d'informations:

[toto@rigel ~]$ pacman -Qi postgresql 
Nom                   : postgresql
Version               : 9.3.2-1
Description           : A sophisticated object-relational DBMS
Architecture          : x86_64
URL                   : http://www.postgresql.org/
Licences              : custom:PostgreSQL
Groupes               : --
Fournit               : akonadi-backend
Dépend de             : postgresql-libs>=9.3.2  krb5  libxml2  readline>=6.0  openssl>=1.0.0
Dépendances opt.      : python3: for PL/Python support [installé]
                        perl: for PL/Perl support [installé]
                        tcl: for PL/Tcl support [installé]
                        postgresql-old-upgrade: upgrade from previous major version using pg_upgrade    

Nous avons besoin de postgresql-old-upgrade,  mais cette dépendance optionnelle semble ne pas être fournie.
Qu'à cela ne tienne: allons rechercher l'ancien paquet dans le cache de pacman:

[toto@rigel ~]$ cp /var/cache/pacman/pkg/postgresql-9.2.4-2-x86_64.pkg.tar.xz Downloads/
[toto@rigel ~]$ cd Downloads/
[toto@rigel Downloads]$ mkdir postgresql
[toto@rigel Downloads]$ tar xpvf postgresql-9.2.4-2-x86_64.pkg.tar.xz -C postgresql

Évidemment si le cache a été vidé, au lieu de simplement utiliser la commande cp, il faudra télécharger le paquet ad hoc (postgresql-9.2.4-2-x86_64.pkg.tar.xz)

Après extraction du paquet, exécutons pg_upgrade (en tant qu'utilisateur postgres) et puis recopions ce qui convient:

[postgres@rigel ~]$ pg_upgrade -b /home/toto/Downloads/postgresql/usr/bin -B /usr/bin/ -d data_9.2/ -D data
[postgres@rigel ~]$ cp data_9.2/pg_hba.conf data
[postgres@rigel ~]$ cp data_9.2/pg_ident.conf data

Il reste éventuellement à adapter le fichier /var/lib/postgres/data/postgresql.conf et en tout cas à décommenter la ligne

port = 5432  

avant de démarrer le serveur comme ceci:


[root@rigel ~]# systemctl start postgresql.service  

ou comme cela

[postgres@rigel ~]$ pg_ctl start -D /var/lib/postgres/data
serveur en cours de démarrage
[postgres@rigel ~]$ LOG:  le système de bases de données a été arrêté à 2014-01-04 16:15:19 CET
LOG:  lancement du processus autovacuum
LOG:  le système de bases de données est prêt pour accepter les connexions

La deuxième commande donne plus d'infos en cas de problème.
Par exemple on peut avoir:

[postgres@rigel ~]$ pg_ctl start -D /var/lib/postgres/data
serveur en cours de démarrage
[postgres@rigel ~]$ FATAL:  n'a pas pu créer le fichier verrou « /run/postgresql/.s.PGSQL.5432.lock » : Aucun fichier ou dossier de ce type

alors que la commande systemctl ne fournit aucun retour bien que le service ne soit pas démarré.
Dans ce cas, il faut automatiser la création du dossier /run/postgresql en procédant comme indiqué ici.
Le dossier sera disponible après redémarrage.

mardi 31 décembre 2013

systemd: création répertoire dans /run

Nous voulons que notre serveur postgresql utilise un socket situé /run/postgresql.
Mais ce n'est pas ce qui est prévu au niveau de la distribution: /run/postgresql n'existe pas et donc notre serveur se plante.
Créer /run/postgresql par mkdir est d'une utilité toute relative car /run se trouve en mémoire vive et le répertoire aura disparu au prochain démarrage.
Il faudrait donc créer ce répertoire au démarrage.
Voici comment procéder si la distribution utilise systemd.
Dans /usr/lib/tmpfiles.d/, créer un fichier postgresql.conf contenant:

d /run/postgresql 2755 postgres postgres -

Par exemple comme ceci:



(Il reste à appuyer sur CTRL-D pour procéder)

Il faut ensuite s'assurer que le service postgresql sera bien activé au prochain démarrage:

[root@rigel ~]# systemctl enable postgresql.service

Bien sûr: ce est écrit ici peut être utilisé dans d'autre cas.
Il est également possible de créer des fichiers.

Pour plus de détails: man tmpfiles.d 

dimanche 29 décembre 2013

Postgresql upgrade

Lors du passage de Fedora 19 à Fedora 20, postgresql passe de la version 9.2 à la version 9.3
Aussi nous devons procéder manuellement à la migration des données postgresql.
Avant toute chose vérifions que la variable d'environnement PGDATA existe et qu'elle contient ce qui convient:

[toto@rigel ~]$ echo $PGDATA
/var/lib/pgsql/data

Ceci sera le cas si nous avons placé dans /etc/profile.d  un fichier pgsql.sh comme expliqué ici.

Installons postgresql-upgrade (si celui-ci ne l'est pas):

[toto@rigel ~]$ su -
Mot de passe :
[root@rigel ~]# yum install postgresql-upgrade

Nous serons amené à agir en tant qu'utilisateur postgres. Le plus simple pour ce faire est de procéder dans une autre fenêtre.


[toto@rigel ~]$ su -
Mot de passe :
[root@rigel ~]# su - postgres
-bash-4.2$ mv /var/lib/pgsql/data/ /var/lib/pgsql/data_9.2/

Nous avons renommé les anciennes données.
Ensuite (en tant que root):

[root@rigel ~]# postgresql-setup initdb

Puis dans la fenêtre où l'on est postgres:

-bash-4.2$ cp /var/lib/pgsql/data_9.2/pg_hba.conf /var/lib/pgsql/data/
-bash-4.2$ pg_upgrade -b /usr/lib64/pgsql/postgresql-9.2/bin/ -B /usr/bin/ -d data_9.2/ -D data

Tout semble se dérouler à merveille.
Et soudain l'erreur fatale:

lc_collate cluster values do not match:  old "fr_FR.UTF-8", new "fr_FR.utf8"

Il faut recommencer après avoir remplacé utf8 par UTF-8 dans /etc/locale.conf

[root@rigel ~]# sed -i 's/utf8/UTF-8/' /etc/locale.conf
[root@rigel ~]# rm -rf /var/lib/pgsql/data
[root@rigel ~]# postgresql-setup initdb

Cette fois, l'étape suivant ne pose aucun problème.
Ne pas oublier de recopier pg_ident.conf (si celui-ci est utilisé):

-bash-4.2$ cp /var/lib/pgsql/data_9.2/pg_ident.conf /var/lib/pgsql/data/

et aussi d'adapter éventuellement le fichier postgresql.conf suivant par exemple ce qui est expliqué ici.
Reste à démarrer le service:

[root@rigel]# systemctl start postgresql.service

mardi 10 décembre 2013

Le piège de la mise à jour cachée

Pignouf Anatole (matricule 1007) a obtenu au sein de l'entreprise une belle promotion: il passe du service "Relations publiques" au service "Recherche" avec à la clef une augmentation de salaire dont le calcul s'effectuera dorénavant sur base de l'échelle 11r.
Il s'occupera du projet "Lave-linge à pédales", projet porteur puisque synonyme d'économie d'énergie.
Reste à mettre à jour les données informatique via un formulaire libreoffice connecté à la base de données PostgreSQL utilisée par l'entreprise:


Dans la table qui sera mise à jour, "Service" et "Projet" apparaissent sous forme de code, mais l'utilisation de listes déroulantes fait que ces codes sont transparents pour l'utilisateur.
Ce qui est affiché à l'écran sous forme d'un seul formulaire est en fait composé d'un formulaire maître "Sélection" et de deux sous-formulaires: "Employés" et "Gestion".


La table "sélection" source de données de "Sélection" contient un matricule qui est sans arrêt mis à jour et qui sert à appeler le dossier désiré. La façon dont tout cela fonctionne est expliqué ici.
Après avoir procédé, la personne chargée d'actualiser les données informatiques en ce qui concerne "Service" et "Projet", clique sur la petite disquette (qui a pris des couleurs) de la barre d'outils:


  ce qui donne:


Il constate alors que depuis un autre poste de travail les données "Ancienneté" et "Échelle de traitement" ont été modifiées (ce qui montre d'ailleurs que chaque enregistrement s'accompagne d'une relecture des données).
Parfait: de toute façon ce n'était pas son job de le faire!
Supposons maintenant que au lieu de cliquer sur l'icône "disquette", l'encodeur appuie sur "Enter" autant de fois qu'il le faut (3 fois) pour amener le focus sur la zone de saisie "matricule". Dès l'instant où le focus quitte le sous-formulaire "Gestion", les données s'enregistrent et nous arrivons à ceci:


L'ancienneté affichée est bien 9, par contre en ce qui concerne l'échelle de traitement on a 12.
Et voilà, le piège s'est refermé! Le piège de la mise à jour cachée!
L'échelle de traitement a été dans un premier temps portée à la valeur '11r' depuis un autre poste, mais ensuite  elle est revenue à la valeur '12'.
Mais pour notre encodeur l'échelle de traitement a toujours été à '12' et il n'a touché à rien. il s'agit donc bien d'un piège et d'une mise à jour cachée.
D'autre part, la personne qui a porté l'échelle de traitement à la valeur '11r' croit avoir fait son travail et elle n'y reviendra plus.
Pour éviter le piège, on peut choisir "Tabulation = non" au niveau des propriétés du contrôle:


ce qui n'empêchera pas que l'on puisse mettre à jour la donnée, à moins de choisir "En lecture seule = OUI".

NB: le piège a été testé avec une grandeur de type character ce qui est le cas de l'échelle de traitement.

samedi 7 décembre 2013

Transfert de colonne

La table "employés" telle que considérée jusqu'à présent (par exemple ici) présente une anomalie, une atteinte à la normalité: la colonne "service" (qui donne sous forme d'un code le service auquel appartient l'employé) est la seule qui contienne des données se rapportant à l'entreprise.

Transfert vers une nouvelle table

On peut envisager de créer une nouvelle table destinée à contenir les données qui sont à la fois relatives à l'employé et à l'entreprise :

CREATE TABLE gestion (
    matricule INTEGER PRIMARY KEY REFERENCES employés,
    service CHAR(2) REFERENCES services,
    projet CHAR(4) REFERENCES projets,
    barème CHAR(4),
    ancienneté SMALLINT
);

Étant donné les relations  d'intégrité référentielle qui figurent dans l'instruction ci-dessus, la table "projets" destinée à contenir en clair le nom des projets doit bien sûr avoir été préalablement créée:

CREATE TABLE projets (
    projet_id CHAR(4) PRIMARY KEY,
    dénomination CHAR VARYING(25)
);

Avant de supprimer la colonne "service" de la table employés, il faut d'abord en transférer les données vers la nouvelle table gestion.
Nous pouvons procéder avec cette instruction SQL:

insert into gestion (matricule, service)
 select matricule, service
 from employés
 order by matricule
 ;

ou dans un terminal psql (nous utilisons PostgreSQL) avec la méta-commande \copy:

\copy employés (matricule, service) to matr-serv
\copy gestion (matricule, service) from matr-serv

Se connectant  en tant que super-utilisateur postgresql, nous pouvons utiliser la commande COPY:


Notons que le fichier de destination sera créé sur le serveur (même si sur la machine client existe un /var/lib/postgresql).
Ce fichier aura comme propriétaire postgres: il faut donc indiquer un chemin conduisant là où postgres a le droit d'écrire. 
Si le volume de données à traiter est très important, cette solution est à privilégier puisqu'elle évite qu'un nombre de données important ne transite par la connexion client/serveur. 

Transfert vers une table existante

Nous avons transféré le contenu de la colonne "service"  depuis la table "employés" vers une table nouvellement créée.
Nous pouvons aussi considérer que la table cible (gestion) existe déjà.
Ajoutons-y la colonne service:

ALTER TABLE gestion
ADD COLUMN service CHAR(2) REFERENCES services
;

Les relations d'intégrité référentielle existantes impliquent que tous les matricules de la table "gestion" correspondent à des matricules de la table "employés", mais l'inverse n'est pas nécessairement vrai.
Il convient tout d'abord d'insérer dans "gestion" les matricules qui n'y existent pas:

insert into gestion (matricule, service)
 select matricule, service
 from employés
 where not exists
 (select *
  from gestion
  where gestion.matricule = employés.matricule)
 order by matricule
 ;

Les rangées nouvellement insérées dans la table gestion possèdent la bonne valeur de "service" (celle de la table employés). Pour toutes les autres rangées, "service" a la valeur NULL.
Il faut donc effectuer une mise à jour, avec par exemple l'instruction SQL:

UPDATE gestion 
SET service = (SELECT service
FROM employés
WHERE employés.matricule = gestion.matricule)
 ;

Mais alors toutes les rangées (dont les nouvelles) seraient concernées par la mise à jour.
Aussi nous préférons agir plus finement avec cette instruction:

UPDATE gestion
SET service = employés.service
FROM employés
WHERE employés.matricule = gestion.matricule
AND   employés.service <> gestion.service

;

(Remarque: l'utilisation de la clause FROM dans une instruction UPDATE n'est pas autorisée dans le langage SQL standard)

Procédons (après avoir mis l'instruction SQL dans le fichier update-gestion.sql):


Une seule rangée mise à jour! Il y a un problème: nous sommes tombés dans le piège du null.
La seule mise à jour effectuée est due certainement à ce que "service" a changé dans la table "employés" pour une des rangées insérées.
Recommençons après avoir modifié l'instruction pour éviter le piège:



Tout est maintenant en ordre: il reste à supprimer la colonne "service" de la table "employés":

ALTER TABLE employés
DROP service
;

Adaptation des formulaires libreoffice

Évidemment dès cet instant le nom du service ne s'affiche plus dans les formulaires que nous avons considérés  ici et :


C'est normal puisque la zone de liste (listbox) qui fournit en clair le nom du service dépend du sous-formulaire "Employés" dont la source de données est la table "employés":


Nous allons régler le problème en cliquant droit sur l'icône du formulaire "Employés", en vue d'y rattacher un nouveau formulaire



que nous appellerons "Gestion"


La source de données en sera la table "gestion" et le lien avec "Employés" sera basé sur "matricule"


Il reste à effectuer un glisser-déposer des icônes qui conviennent vers le formulaire "Gestion":


Et voilà: