Spécificités des types de données

Spécificités des types de données #

Manipulation des types VARCHAR #

Pour Oracle, une chaine vide est aussi une chaîne NULL. Elle a les deux propriétés à la fois. PostgreSQL fait la différence : soit la chaîne est inconnue (IS NULL) soit elle est vide.

Certaines requêtes donnant satisfaction sous Oracle peuvent donner des résultats faux lorsqu’elles sont portées directement. Les cas les plus courants sont la comparaison de la valeur d’une colonne avec une chaîne vide et la concaténation avec une valeur NULL.

Comparaison #

Pour Oracle, si la colonne col est un VARCHAR2, les deux requêtes suivantes vont retourner le même résultat :

SELECT * FROM TABLE WHERE col = '';
SELECT * FROM TABLE WHERE col IS NULL;

Mais sous PostgreSQL, les deux requêtes ne retourneront pas le même résultat. Ora2Pg transpose les valeurs NULL des colonnes en VARCHAR2 en valeur NULL pour un type VARCHAR. La première requête ne retournera aucun résultat.

Il est donc nécessaire de réécrire la requête concernée en utilisant les opérateurs IS NULL ou IS NOT NULL. Dans ce cas, la requête pourra utiliser un index pour la recherche.

Si la comparaison est transposée avec une fonction COALESCE et en conservant la comparaison avec la chaîne vide, il ne sera pas possible d’utiliser un index pour la recherche.

EXPLAIN SELECT * FROM emp2 WHERE ename IS NULL;
--                                QUERY PLAN                                
-- -------------------------------------------------------------------------
--  Index Scan using emp2_ename on emp2  (cost=0.00..12.87 rows=1 width=20)
--    Index Cond: (ename IS NULL)

EXPLAIN SELECT * FROM emp2 WHERE COALESCE(ename) = '';
--                          QUERY PLAN                          
-- -------------------------------------------------------------
--  Seq Scan on emp2  (cost=0.00..79144.81 rows=20972 width=20)
--    Filter: ((COALESCE(ename))::text = `::text)

Concaténation #

Du fait de la spécificité du type VARCHAR2 d’Oracle, la concaténation d’une valeur NULL dans une chaîne de caractères ne pose pas de problèmes. Elle en pose cependant dans PostgreSQL. Le standard SQL définit en effet que pour la plupart des fonctions, un paramètre NULL entraîne un résultat NULL (on parle de fonctions STRICT dans PostgreSQL). Dans le cas présent, une valeur NULL dans une opération de concaténation sera propagée au résultat : le résultat sera une chaîne NULL et non la chaîne de caractères attendue.

On prendra donc garde à ajouter la fonction COALESCE dans les portions de code touchées par ce problème :

SELECT 'nom employé: ' || COALESCE(ename, `) FROM emp;

Manipulation de dates #

Format de sortie #

Pour Oracle, le format défini par NLS_DATE_FORMAT détermine le format des dates qui sera utilisé pour la sortie des fonctions TO_CHAR() et TO_DATE().

Concernant PostgreSQL, par défaut, le format de sortie d’une date est conforme au standard SQL: YYYY-MM-DD HH24:MI:SS.mmmmmmm+TZ. Il est cependant possible de le modifier avec la variable de configuration DateStyle (par défaut ISO, DMY).

Opérations sur les dates #

Oracle autorise l’ajout ou la soustraction d’un nombre entier à une date. Par exemple :

SELECT SYSDATE + 1 FROM DUAL;

retournera la date de demain. Pour le type date de PostgreSQL, le comportement est identique, mais les deux types date ne le sont pas.

Pour obtenir le même résultat avec un TIMESTAMP (l’équivalent du type DATE d’Oracle) sous PostgreSQL, il faut utiliser un INTERVAL :

SELECT now() + INTERVAL '1 DAY';

De même, la soustraction d’un TIMESTAMP à un autre retourne un nombre correspondant au nombre de jour entre ces deux dates, alors que, sous PostgreSQL, cette opération retourne un intervalle.

Portage de SYSDATE #

Attention au type de données DATE sous Oracle, c’est en fait du TIMESTAMP WITHOUT TIMEZONE.

SELECT to_char(sysdate,'DD/MM/YYYY HH24:MI:SS') FROM dual;

-- TO_CHAR(SYSDATE,'DD
-- -------------------
-- 11/03/2011 14:58:22

Il convient donc d’utiliser LOCALTIMESTAMP (et pas current_timestamp qui, lui, contient la timezone…) :

SELECT LOCALTIMESTAMP;
--          timestamp          
-- ----------------------------
--  2011-03-11 16:59:29.889823

Ainsi, toute variable déclarée en DATE dans du PL/SQL d’Oracle doit être déclarée en TIMESTAMP dans du PL/pgsql de PostgreSQL.


Précédent
Portage des requêtes SQL
Suivant
Jointures