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?
3 Réponses :
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 ...
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;
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!!
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);
Merci beaucoup pour votre aide à ce sujet. Excellent travail et très utile.