Oracle
 sql >> Base de données >  >> RDS >> Oracle

Oracle SQL-Loader gère efficacement les doubles guillemets internes dans les valeurs

Si vous n'avez jamais eu de tuyaux dans les champs fermés, vous pouvez le faire à partir du fichier de contrôle. Si vous pouvez avoir à la fois des tubes et des guillemets doubles dans un champ, je pense que vous n'avez malheureusement pas d'autre choix que de prétraiter les fichiers.

Votre solution [1], pour remplacer les guillemets doubles avec un opérateur SQL , arrive trop tard pour être utile ; les délimiteurs et les encadrements ont déjà été interprétés par SQL*Loader avant qu'il n'exécute l'étape SQL. Votre solution [2], pour ignorer l'enceinte, fonctionnerait en combinaison avec [1] - jusqu'à ce que l'un des champs contienne un caractère pipe. Et la solution [3] a les mêmes problèmes que l'utilisation de [1] et/ou [2] globalement.

La documentation pour spécification des délimiteurs mentionne que :

En d'autres termes, si vous avez répété les guillemets doubles à l'intérieur les champs seraient alors échappés et apparaîtraient dans les données de la table. Comme vous ne pouvez pas contrôler la génération de données, vous pouvez prétraiter les fichiers que vous obtenez pour remplacer tous les guillemets doubles par des guillemets doubles échappés. Sauf que vous ne voulez pas remplacer tous d'entre eux - ceux qui sont en fait de véritables enclos ne doivent pas être échappés.

Vous pouvez utiliser une expression régulière pour cibler les caractères pertinents en sautant les autres. Ce n'est pas mon domaine de prédilection, mais je pense que vous pouvez le faire avec assertions avant et arrière .

Si vous aviez un fichier appelé orig.txt contenant :

"1"|A|"B"|"C|D"
"2"|A|"B"|"C"D"
3|A|""B""|"C|D"
4|A|"B"|"C"D|E"F"G|H""

vous pourriez faire :

perl -pe 's/(?<!^)(?<!\|)"(?!\|)(?!$)/""/g' orig.txt > new.txt

Cela recherche un guillemet double qui n'est pas précédé de l'ancre de début de ligne ou d'un caractère pipe ; et n'est pas suivi d'un caractère pipe ou d'une ancre de fin de ligne ; et remplace uniquement ceux avec des guillemets doubles échappés (doublés). Ce qui ferait new.txt contenir :

"1"|A|"B"|"C|D"
"2"|A|"B"|"C""D"
3|A|"""B"""|"C|D"
4|A|"B"|"C""D|E""F""G|H"""

Les guillemets au début et à la fin des champs ne sont pas modifiés, mais ceux du milieu sont désormais échappés. Si vous avez ensuite chargé cela avec un fichier de contrôle avec des guillemets doubles :

load data
truncate
into table t42
fields terminated by '|' optionally enclosed by '"'
(
  col1,
  col2,
  col3,
  col4
)

Vous vous retrouveriez alors avec :

select * from t42 order by col1;

      COL1 COL2       COL3       COL4                
---------- ---------- ---------- --------------------
         1 A          B          C|D                 
         2 A          B          C"D                 
         3 A          "B"        C|D                 
         3 A          B          C"D|E"F"G|H"        

qui, espérons-le, correspond à vos données d'origine. Il peut y avoir des cas extrêmes qui ne fonctionnent pas (comme un guillemet double suivi d'un tube dans un champ) mais il y a une limite à ce que vous pouvez faire pour essayer d'interpréter les données de quelqu'un d'autre... Il peut aussi y avoir (beaucoup) de meilleurs modèles d'expressions régulières, bien sûr.

Vous pouvez également envisager d'utiliser une table externe au lieu de SQL*Loader, si le fichier de données est (ou peut être) dans un répertoire Oracle et que vous avez les bonnes permissions. Vous devez toujours modifier le fichier, mais vous pouvez le faire automatiquement avec le preprocessor plutôt que d'avoir à le faire explicitement avant d'appeler SQL*Loader.