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

Nouvelles lignes indésirables lors de la mise en file d'attente d'un résultat sqlplus dans un fichier xml

Comme @kfinity l'a suggéré, cela est lié à la gestion de CLOB, mais aussi à la façon dont dbms_output œuvres. Vous lisez le CLOB en morceaux de 32k et écrivez chacun de ces morceaux avec put_line() , qui ajoute un caractère de saut de ligne après chaque bloc de 32 ko. Ceux-ci ne sont alignés sur aucun saut de ligne existant dans votre document XML, vous obtenez donc les sauts de ligne d'origine, puis des sauts supplémentaires - qui semblent quelque peu aléatoires et au milieu du texte, mais qui se trouvent en fait à des endroits prévisibles.

Une solution évidente consiste à passer de put_line() à put() , mais cela cassera la taille maximale du tampon et lancera quelque chose comme "ORU-10028 :dépassement de longueur de ligne, limite de 32 767 octets par ligne".

Plutôt que de lire en morceaux fixes de 32k, vous pouvez lire une ligne à la fois; le CLOB ne comprend pas vraiment les lignes en tant que telles, mais vous pouvez rechercher des sauts de ligne, quelque chose comme :

WHILE pos < v_clob_length LOOP
  -- read to next newline if there is one, rest of CLOB if not
  if dbms_lob.instr(v_clob, chr(10), pos) > 0 then
    amount := dbms_lob.instr(v_clob, chr(10), pos) - pos;
    dbms_lob.read(v_clob, amount, pos, buffer);
    pos := pos + amount + 1; -- skip newline character
  else
    amount := 32767;
    dbms_lob.read(v_clob, amount, pos, buffer);
    pos := pos + amount;
  end if;

  dbms_output.put_line(buffer);
END LOOP;

Le if recherche un caractère de nouvelle ligne, après la position actuelle. S'il en trouve un, le montant est calculé comme le nombre de caractères de la position actuelle à cette nouvelle ligne (ou plutôt, moins un - car vous ne voulez pas que la nouvelle ligne elle-même), il lit autant de caractères, puis ajuste la position par le montant lu plus un (pour ignorer la nouvelle ligne - dont vous ne voulez/n'avez pas besoin comme put_line() en ajoute un encore).

S'il n'en trouve pas, il lit jusqu'à 32 000 - avec un peu de chance, une seule fois. s'il y a plus que cela, il peut rester des caractères sans saut de ligne, alors il fera une deuxième lecture mais ajoutera toujours cette nouvelle ligne supplémentaire et cassera cette ligne. Vous ne pouvez pas faire grand-chose à ce sujet en utilisant dbms_output cependant, vous devrez passer à utl_file écrire sur le serveur au lieu de spouler sur le client.