fr en

Créer un fichier à partir des données d'un spool avec SQL

Objectifs :

Il est, parfois, intéressant de pouvoir récupérer des données à partir de fichiers édités (spool file).
C’est le cas lorsqu’il faut récupérer les données extraites par des commandes CL génèrant une édition (OUTPUT *PRINT) où lorsqu’il faut analyser des spools générés par d’autres traitements.

Ceci est facilement réalisable avec SQL.

Pour cela, 3 étapes sont nécessaires :

  • Rechercher et identifier le spool à traiter.
  • Extraire les données du spool à traiter.
  • Générer un fichier avec les données du spool mises en forme. 

Identification du spool à traiter :

La fonction table QSYS2.SPOOLED_FILE_INFO permet de lister les spools présents sur une machine.
Elle permet donc de récupérer les identifiants d’un spool spécifique.
Ce sont ces identifiants qui seront ensuite utilisés pour cibler le spool à traiter.

Les identifiants d’un fichier spool, portés par la fonction table QSYS2.SPOOLED_FILE_INFO, sont :

  • SPOOLED_FILE_NAME : Nom du fichier spool
  • SPOOLED_FILE_NUMBER : Numéro du spool
  • QUALIFIED_JOB_NAME : Identifiant complet du job ayant généré le spool.
    Cet identifiant est composé ainsi : Numéro du job / Utilisateur du job / Nom du job
  • JOB_NAME : Nom du job
  • JOB_USER : Utilisateur du job
  • JOB_NUMBER : Numéro du job

Exemples d’utilisation de la fonction table QSYS2.SPOOLED_FILE_INFO :

  1. Lister tous les spools de la machine
    SELECT 
    SPOOLED_FILE_NAME, 
    SPOOLED_FILE_NUMBER, 
    STATUS, 
    TOTAL_PAGES, 
    QUALIFIED_JOB_NAME, 
    JOB_NAME, 
    JOB_USER, 
    JOB_NUMBER, 
    OUTPUT_QUEUE, 
    OUTPUT_QUEUE_LIBRARY 
    FROM TABLE(QSYS2.SPOOLED_FILE_INFO(USER_NAME => ‘*ALL’));

  2. Lister tous les spools de l’utilisateur en cours
    SELECT 
    SPOOLED_FILE_NAME, 
    SPOOLED_FILE_NUMBER, 
    STATUS, 
    TOTAL_PAGES, 
    QUALIFIED_JOB_NAME, 
    JOB_NAME, 
    JOB_USER, 
    JOB_NUMBER, 
    OUTPUT_QUEUE, 
    OUTPUT_QUEUE_LIBRARY 
    FROM TABLE(QSYS2.SPOOLED_FILE_INFO(USER_NAME => ‘*CURRENT’));

  3. Lister tous les spools d’un utilisateur donné, par exemple les spools de l’utilisateur mon_user
    SELECT 
    SPOOLED_FILE_NAME, 
    SPOOLED_FILE_NUMBER, 
    STATUS, 
    TOTAL_PAGES, 
    QUALIFIED_JOB_NAME, 
    JOB_NAME, 
    JOB_USER, 
    JOB_NUMBER, 
    OUTPUT_QUEUE, 
    OUTPUT_QUEUE_LIBRARY 
    FROM TABLE(QSYS2.SPOOLED_FILE_INFO(USER_NAME => ‘mon_user‘));

  4. Lister tous les spools du job en cours
    SELECT 
    SPOOLED_FILE_NAME, 
    SPOOLED_FILE_NUMBER, 
    STATUS, 
    TOTAL_PAGES, 
    QUALIFIED_JOB_NAME, 
    JOB_NAME, 
    JOB_USER, 
    JOB_NUMBER, 
    OUTPUT_QUEUE, 
    OUTPUT_QUEUE_LIBRARY 
    FROM TABLE(QSYS2.SPOOLED_FILE_INFO(JOB_NAME => ‘*’));

  5. Lister tous les spools d’un job donné
    Exemple pour le job :
    JOB_NAME : mon_job_name
    JOB_USER : mon_job_user
    JOB_NUMBER : mon_job_number

    SELECT 
    SPOOLED_FILE_NAME, 
    SPOOLED_FILE_NUMBER, 
    STATUS, 
    TOTAL_PAGES, 
    QUALIFIED_JOB_NAME, 
    JOB_NAME, 
    JOB_USER, 
    JOB_NUMBER, 
    OUTPUT_QUEUE, 
    OUTPUT_QUEUE_LIBRARY 
    FROM TABLE(QSYS2.SPOOLED_FILE_INFO(JOB_NAME => ‘*ALL’))
    WHERE QUALIFIED_JOB_NAME = ‘mon_job_number/mon_job_user/mon_job_name‘);

    Ou

    SELECT 
    SPOOLED_FILE_NAME, 
    SPOOLED_FILE_NUMBER, 
    STATUS, 
    TOTAL_PAGES, 
    QUALIFIED_JOB_NAME, 
    JOB_NAME, 
    JOB_USER, 
    JOB_NUMBER, 
    OUTPUT_QUEUE, 
    OUTPUT_QUEUE_LIBRARY 
    FROM TABLE(QSYS2.SPOOLED_FILE_INFO(JOB_NAME => ‘*ALL’))
    WHERE JOB_NUMBER = mon_job_number
    AND JOB_USER = mon_job_user
    AND JOB_NAME =mon_job_name;

  6. Récupérer le dernier spool généré par un job donné
    Exemple pour le job :
    JOB_NAME : mon_job_name
    JOB_USER : mon_job_user
    JOB_NUMBER : mon_job_number

    SELECT 
    SPOOLED_FILE_NAME, 
    SPOOLED_FILE_NUMBER, 
    STATUS, 
    TOTAL_PAGES, 
    QUALIFIED_JOB_NAME, 
    JOB_NAME, 
    JOB_USER, 
    JOB_NUMBER, 
    OUTPUT_QUEUE, 
    OUTPUT_QUEUE_LIBRARY 
    FROM TABLE(QSYS2.SPOOLED_FILE_INFO(JOB_NAME => ‘*ALL’))
    WHERE JOB_NUMBER = mon_job_number
    AND JOB_USER = mon_job_user
    AND JOB_NAME =mon_job_name
    ORDER BY
    CREATION_TIMESTAMP DESC
    FETCH FIRST ROW ONLY;

Extraction des données du spool à traiter :

Une fois le spool à traité identifier, il suffit de requêter la fonction table SYSTOOLS.SPOOLED_FILE_DATA pour récupérer les données du spool.
La fonction table SYSTOOLS.SPOOLED_FILE_DATA ne contient que 2 champs :

  • ORDINAL_POSITION : qui correspond au numéro de ligne éditée (sans prise en compte des sauts de lignes ou des sauts de pages)
  • SPOOLED_DATA : qui correspond au contenu de la ligne éditée

Pour cibler le spool à traiter lors de la réquête sur la table fonction SYSTOOLS.SPOOLED_FILE_DATA il faut utiliser les identifiants suivants :

  • JOB_NAME : qui correspond au QUALIFIED_JOB_NAME récupérer dans la fonction table QSYS2.SPOOLED_FILE_INFO
    C’est à dire : Numéro du Job + ‘/’ + Utilisateur du Job + ‘/’ Nom du Job
  • SPOOLED_FILE_NAME : nom du spool.
    C’est le nom du spool récupérer avec la fonction table QSYS2.SPOOLED_FILE_INFO
  • SPOOLED_FILE_NUMBER : numéro du spool.
    Il est lui aussi récupéré depuis la fonction table QSYS2.SPOOLED_FILE_INFO

Exemple avec le fichier spool suivant :
JOB_NAME : mon_job_name
JOB_USER : mon_job_user
JOB_NUMBER : mon_job_number
SPOOLED_FILE_NAME : mon_spooled_file_name
SPOOLED_FILE_NUMBER : mon_spooled_file_number

SELECT ORDINAL_POSITION, SPOOLED_DATA
FROM TABLE(SYSTOOLS.SPOOLED_FILE_DATA(JOB_NAME => ‘mon_job_number/mon_job_user/mon_job_name‘, SPOOLED_FILE_NAME =>’mon_spooled_file_name‘, SPOOLED_FILE_NUMBER => mon_spooled_file_number))
ORDER BY ORDINAL_POSITION;

Le résultat obtenu est :

Le résultat obtenu correspond totalement au données éditées.
Mais il est peu exploitable car :

  • le champ SPOOLED_DATA contient l’intégralité de la ligne éditée
  • Les lignes 1 et 11 sont des lignes propres à l’édition (Date, N° de page, ligne de fin d’édition) qu’il n’est peut-etre pas utile d’extraire.

Génération d'une table à partir des données du spool mises en forme

Les données du spool étant extractables, il ne reste plus qu’à les mettre en forme et à faire un CREATE TABLE pour générer une table propre avec les données issues du spool.

Exemple avec les données du spool précédent :

  • Suppression du fichier à générer
    DROP TABLE QTEMP.TB_SPOOL;
  • Création de la table avec définition des champs à extraire de SPOOLED_DATA 
    CREATE TABLE QTEMP.TB_SPOOL (
    PAYS CHARACTER (20) NOT NULL WITH DEFAULT,
    CONTINENT CHARACTER (20) NOT NULL WITH DEFAULT,
    NOMBRE_COUPE CHARACTER (1) NOT NULL WITH DEFAULT);

  • Alimentation de la table à partir des donnés récupérées dans le champ SPOOLED_DATA (découpé avec des substring : SUBSTR)

    INSERT INTO QTEMP.TB_SPOOL (PAYS, CONTINENT, NOMBRE_COUPE)
    SELECT SUBSTR(SPOOLED_DATA, 1, 20),
    SUBSTR(SPOOLED_DATA, 23, 20),
    SUBSTR(SPOOLED_DATA, 52, 1)
    FROM TABLE(SYSTOOLS.SPOOLED_FILE_DATAJOB_NAME => ‘mon_job_number/mon_job_user/mon_job_name‘, SPOOLED_FILE_NAME =>’mon_spooled_file_name‘, SPOOLED_FILE_NUMBER => mon_spooled_file_number))
    WHERE SUBSTR(SPOOLED_DATA, 49, 4) <> ‘PAGE’
    AND SUBSTR(SPOOLED_DATA, 1, 37) <> ‘* * * F I N D U R A P P O R T * * *’
    AND SUBSTR(SPOOLED_DATA, 1, 4) <> ‘PAYS’
    ORDER BY ORDINAL_POSITION;

  • Vérification de la table générée
    SELECT *
    FROM QTEMP.TB_SPOOL;

Le résultat obtenu est une table totalement exploitable, avec 3 champs distincts : PAYS, CONTINENT, NOMBRE_COUPE.