Introduction

Ce document a pour but de décrire l'utilisation des valeurs NULL en base de données.

Seule une table d'une base de données SQL peut contenir des colonnes avec une valeur NULL.

La présentation ci-dessous concerne les programmes Visual Adelia et Web Adelia.

Si vous devez accéder à une base de données qui utilise des valeurs NULL dans ses colonnes, vous devez alors mettre en place la gestion correspondante.

Cependant, nous décrirons un cas particulier valable pour des fonctions sur les colonnes en fin de page que nous vous invitons à lire.

Pour cela, vous avez plusieurs aspects à prendre en compte :

  • Décrire dans votre modèle de données Adelia les colonnes qui autorisent la valeur NULL (Propriété conceptuelle / contrainte SQL = [NULL ; NULL WITH DEFAULT] ou bien Propriété logique / onglet complément / contrainte SQL = [NULL ; NULL WITH DEFAULT] )
  • Vérifier que la colonne contient ou non une valeur NULL après une lecture
  • Positionner ou non une valeur NULL dans la colonne avant de l'écriture
  • Comparer la valeur d'une colonne à NULL dans la condition d'un ordre SQL.

Décrire les données

Exemples de saisie de la contrainte SQL :

  • Niveau conceptuel : 
  • Niveau logique : 

Vérifier la valeur de la colonne

Pour cela, on dispose de la fonction prédéfinie &RECUPERER_INDIC qui s'utilise comme suit :

W_NUM_CLIENT = 123
Lire_Sql Client *Cond(CL_NUM_CLIENT = :W_NUM_CLIENT)
Si *SqlCode = *Normal

   /* ___ La colonne nom du client peut contenir une valeur nulle.
   /* ___ Pour le vérifier, utiliser la fonction avec comme paramètres :
   /* ___   - le nom de l'entité Adelia 
   /* ___   - le nom de la propriété logique
   
   Si &RECUPERER_INDIC(CLIENT;CL_NOM_CLIENT) = 0 

      /* ___ La colonne CL_NOM_CLIENT n'a pas la valeur NULL
      Lire_Sql PRESIDENT *Cond(PR_NOM = :CL_NOM_CLIENT)
      ...
   Sinon
      /* ___ La colonne contient une valeur NULL
      ...
   Fin
Sinon
   ...
Fin

Positionner une valeur NULL dans une colonne

Afin de définir si la valeur d'une colonne contient NULL ou pas, il faut commencer par utiliser l'ordre L4G AFFECTER_INDIC.
Lorsque le premier paramètre contient *VRAI, la valeur qui sera attribuée à la propriété sera positionnée à NULL lors de l'écriture (création ou mise à jour). Dans le cas contraire, elle conservera la valeur contenue dans la variable.
Dans l'utilisation des ordres SQL de création ou de mise à jour, il est obligatoire d'utiliser le mot réservé *INDIC_NULL en paramètre.
Le fait d'utiliser une valeur nulle dépend uniquement de ce qui doit être mise en oeuvre au niveau du métier et permet d'indiquer que la donnée n'est pas renseignée.

Pour une simplification du mode de gestion, vous pourriez mettre en place des règles de gestion qui simplifieraient la gestion des valeurs NULL en utilisant systématiquement une zone de donnée en relation avec les colonnes.

Ci après, deux exemples de mise en oeuvre : 

Exemple 1, sans règle de gestion

Si W_NBR_ENFANT = 0
   Affecter_Indic *Vrai CLIENT CL_NOM_CLIENT
Sinon
   Affecter_Indic *Faux CLIENT CL_NOM_CLIENT
Fin
...
Creer_Sql CLIENT *Indic_Null

Exemple 2, avec une règle de gestion (génération avec RG implicite)

Il faut créer deux règles de gestion :

  • une RG de classe Création
  • une RG de classe Mise à jour.

Contenu de la règle de gestion implicite :

Decl BOOL W_BOO_CL_NOM_CLIENT  /* --- zone de donnée pour la propriété CL_NOM_CLIENT
Affecter_Indic W_BOO_CL_NOM_CLIENT CLIENT CL_NOM_CLIENT

Traitement dans le programme :

W_BOO_CL_NOM_CLIENT = (W_NBR_ENFANT = 0)
...
Creer_Sql CLIENT *Indic_Null

Comparer à NULL la valeur d'une colonne dans une requête SQL

Afin de tester si une colonne vaut NULL dans une requête Sql, on utilisera la fonction scalaire SQL EST_INDIC_NULL directement dans la clause conditionnelle :

W_NUM_CLIENT = 123
Lire_Sql CLIENT *Cond( EST_INDIC_NULL(CL_NOM_CLIENT) Et CL_NUM_CLIENT = :W_NUM_CLIENT) )
Si *SqlCode = *Normal
   /* ___ Le client existe et le nom n'est pas renseigné ___
   ...
Fin

Cas particulier des fonctions sur les colonnes

Certaines fonctions telles que MAX ou bien MIN peuvent retourner une valeur NULL alors que la colonne elle-même n'en gère pas.
Ce cas se produit à partir du moment où la sélection ne retourne pas d'enregistrement.

Pour éviter une erreur SQL (et un éventuel enregistrement dans la log du travail iSeries), nous recommandons d'utiliser une variable indicatrice dans l'ordre SQL.

Par exemple : 

Lire_Sql *Col(MAX(CL_MNT_CREDIT) :W_MNT_CREDIT_MAX) *Cond(CL_CAT_CLIENT = 'A')

Dans le cas où il n'y a pas de catégorie de client égal à 'A' alors une erreur SQL est renvoyée.

Pour éviter cela, il faut écrire : 

Dans le paragraphe de déclaration

Ref(CL_MNT_CREDIT) W_MNT_CREDIT_MAX
Num_Bin_2          W_IND_MAX

Dans un paragraphe de traitement

Lire_Sql *Col(MAX(CL_MNT_CREDIT) :W_MNT_CREDIT_MAX W_IND_MAX) *Cond(CL_CAT_CLIENT = 'A')
Si W_IND_MAX < 0
   /* ___ La valeur renvoyée vaut NULL ___
Sinon
   /* ___ La valeur de W_MNT_CREDIT_MAX est renseignée avec la valeur max des enregistrements liés à la condition ___
Fin