1
votes

Tentative d'écriture de la sortie dans un CSV sur un répertoire, échec avec PLS-00302

J'essaye de produire des informations de surveillance dans un fichier .csv. Je dois m'en tenir au cadre "de base" du code. Le problème est de le faire sortir en .csv / d'obtenir le code à compiler.

J'ai essayé différentes façons de faire cela, maintenant je suis coincé, je me retrouve principalement à déplacer des guillemets et des guillemets doubles.

create or replace procedure WRITE_EST_SIZE_01 is
  file_handle UTL_FILE.file_type;
begin
  file_handle := utl_file.fopen('ESTIMATES_CSV', 
                                'csv_filename' || 
                                   to_char(sysdate,'MONYYYY')||'.csv',
                                'w', 32767);
  for rws in (SELECT 'OWNER' || ',' || 
                     'SEGMENT_NAME' || ',' ||
                     'U' || ',' ||
                     'SUM_BYTES'
                FROM
              union ALL
              select /*+ parallel*/
                     s.owner || ',' ||
                     s.segment_name || ',' ||
                     'U' || ',' ||
                     sum(s.bytes)/1024/1024 
                from DBA_SEGMENTS s
                where s.owner = (select distinct targetschema
                                   from pdu.pdu_table) and
                      s.segment_name in (select table_name
                                           from another_table) and 
                      s.segment_type LIKE '%TABLE%'
                group by s.owner, s.segment_name
              union all
              select /*+ parallel*/
                     i.table_owner || ',' || 
                     i.table_name || ',' ||
                     'I' || ',' ||
                     sum(s.bytes)/1024/1024
                from DBA_SEGMENTS s,
                     DBA_INDEXES  i
                where i.table_owner  = (select distinct targetschema
                                          from pdu.pdu_table) and
                      i.table_name in (select table_name
                                         from another_table) and
                      i.owner = s.owner and
                      i.index_name = s.segment_name and
                      s.segment_type like '%INDEX%'
                group by i.table_owner, i.table_name
              union all
              select /*+ parallel*/
                     l.owner || ',' ||
                     l.table_name || ',' ||
                     'L' || ',' ||
                     sum(s.bytes)/1024/1024
                from DBA_SEGMENTS s,
                     ALL_LOBS l
                where l.owner = (select distinct targetschema
                                   from another_table) and
                      l.table_name in (select table_name
                                         from another_table) and
                      l.owner = s.owner and
                      l.segment_name = s.segment_name
                group by l.owner, l.table_name
                --order by 1, 2)
  loop
    utl_file.put_line(file_handle,
                      rws.OWNER || ',' ||
                      rws.SEGMENT_NAME || ',' ||
                      rws.U || ',' ||
                      rws.SUM_BYTES -- your columns here
                      );
  end loop;

  utl_file.fclose(file_handle);
end WRITE_EST_SIZE_01;

En fait, cela ne compilera pas , mais se plaint que rws.OWNER doit être déclaré. Il compile si je mets tous les rws. entre guillemets, mais la sortie csv est remplacée par tout ce qui est entre guillemets. Quelqu'un peut-il voir un moyen de faire cela par lequel il "va" vider la sortie du sql dans un fichier .csv?


0 commentaires

3 Réponses :


2
votes

Votre requête de curseur effectue la concaténation dans chaque branche de l'union, donc si vous exécutez cette version autonome, vous verrez un ensemble de résultats avec une seule colonne. Lorsque vous essayez de traiter la boucle, vous essayez de rechercher le propriétaire / segment / etc. - mais ils ne font pas partie de la projection à partir de cette requête de curseur.

Si vous attribuez un alias à la seule valeur de colonne générée, au moins dans la première branche:

utl_file.put_line(file_handle, 'OWNER,SEGMENT_NAME,U,SUM_BYTES');

ou plus simplement:

utl_file.put_line(file_handle, rws.CSV_TEXT);

alors dans votre boucle vous pouvez faire référence à cet alias:

SELECT 'OWNER,SEGMENT_NAME,U,SUM_BYTES' AS CSV_TEXT

Bien que ce soit probablement plus simple simplement d'écrire la ligne d'en-tête dans le fichier directement avant la boucle de votre curseur, au lieu de l'intégrer à cette requête:

SELECT 'OWNER'||','||'SEGMENT_NAME'||','||'U'||','||'SUM_BYTES' AS CSV_TEXT

Vous pouvez alors conserver la concaténation dans le reste branches d'union avec le même alias de valeur de colonne unique; ou demandez aux branches d'union d'obtenir les colonnes brutes (propriétaire, etc.) sans concaténation, puis gardez la concaténation à l'intérieur de la boucle. [Comme le fait la réponse de @BobJarvis!] Mais ne faites pas les deux ...


0 commentaires

2
votes

Dans votre SQL, vous créez une chaîne concaténée quand il semble que vous vouliez juste récupérer les champs individuels. Je suggère:

create or replace procedure WRITE_EST_SIZE_01 is
  file_handle UTL_FILE.file_type;
begin
  file_handle := utl_file.fopen('ESTIMATES_CSV', 
                                'csv_filename' || 
                                   to_char(sysdate,'MONYYYY')||'.csv',
                                'w', 32767);
  for rws in (select s.owner,
                     s.segment_name,
                     'U' AS FLAG,
                     sum(s.bytes)/1024/1024 AS SUM_BYTES
                from DBA_SEGMENTS s
                where s.owner = (select distinct targetschema
                                   from pdu.pdu_table) and
                      s.segment_name in (select table_name
                                           from another_table) and 
                      s.segment_type LIKE '%TABLE%'
                group by s.owner, s.segment_name
              union all
              select i.table_owner AS OWNER,
                     i.table_name AS SEGMENT_NAME,
                     'I' AS FLAG,
                     sum(s.bytes)/1024/1024 AS SUM_BYTES
                from DBA_SEGMENTS s,
                     DBA_INDEXES  i
                where i.table_owner  = (select distinct targetschema
                                          from pdu.pdu_table) and
                      i.table_name in (select table_name
                                         from another_table) and
                      i.owner = s.owner and
                      i.index_name = s.segment_name and
                      s.segment_type like '%INDEX%'
                group by i.table_owner, i.table_name
              union all
              select l.owner,
                     l.table_name AS SEGMENT_NAME,
                     'L' AS FLAG,
                     sum(s.bytes)/1024/1024 AS SUM_BYTES
                from DBA_SEGMENTS s,
                     ALL_LOBS l
                where l.owner = (select distinct targetschema
                                   from another_table) and
                      l.table_name in (select table_name
                                         from another_table) and
                      l.owner = s.owner and
                      l.segment_name = s.segment_name
                group by l.owner, l.table_name
                --order by 1, 2)
  loop
    utl_file.put_line(file_handle,
                      rws.OWNER || ',' ||
                      rws.SEGMENT_NAME || ',' ||
                      rws.FLAG || ',' ||
                      rws.SUM_BYTES -- your columns here
                      );
  end loop;

  utl_file.fclose(file_handle);
end WRITE_EST_SIZE_01;


4 commentaires

Vous pouvez ajouter utl_file.put_line (file_handle, 'OWNER, SEGMENT_NAME, U, SUM_BYTES'); avant la boucle pour générer la ligne d'en-tête?


@AlexPoole Merci Alex. Il compile, jusqu'à ce que j'ajoute dans l'utl_file.put_line (file_handle, 'OWNER, SEGMENT_NAME, U, SUM_BYTES'); avant la boucle. Est-ce que c'est censé entrer, tout simplement, ou est-ce que je suis censé supprimer un peu avant d'ajouter cela?


@Dave - Je ne voulais pas dire immédiatement avant le mot-clé loop , je voulais dire tavant toute la structure de la boucle - donc ça va entre le utl_file.fopen (...); et pour les rws dans ... .


@AlexPoole - Merci Alex, ça fonctionne maintenant. Apprécier ton aide!!



2
votes

Lorsque vous écrivez:

...
) loop
utl_file.put_line(file_handle, rws._row_data);

vous utilisez des noms de colonnes qui devraient être décrits dans la requête à l'intérieur de pour rws dans (select ...) loop . Actuellement, cette instruction SELECT n'a qu'une seule colonne dont le nom est automatiquement généré. Vous devez le changer en:

for rws in (SELECT 'OWNER,SEGMENT_NAME,U,SUM_BYTES' row_data
                FROM
              union ALL

De plus, vous devez modifier toutes les autres sous-requêtes de cette manière.

Ou, vous pouvez conserver cette requête en tant que est, sauf un petit changement:

SELECT 'OWNER' owner, 'SEGMENT_NAME' segment_name, 'U' u, 'SUM_BYTES' sum_bytes
  FROM dual
 union all
select /*+ parallel*/
       s.owner, s.segment_name, 'U', sum(s.bytes)/1024/1024 
  from ...

Et changez la dernière ligne:

   ) loop
utl_file.put_line(file_handle, rws.OWNER||','||rws.SEGMENT_NAME||','||rws.U||','||rws.SUM_BYTES);


1 commentaires

Merci beaucoup pour votre aide à ce sujet. Excellent travail et très utile.