Search code examples
sqloracle-databasereportsqlplus

Formatting output in a report on SQL*Plus (after spool to CSV)


I have a question about formatting the output in a report that I get from csv that was spooled from SQL*Plus. I have Initial table whose data looks like this:

ord_no ls_prod_division ls_prod_area ls_prod_family_name ls_prod_family_code ls_prod_generic_name ls_brand_name ls_reference_prod ls_description ls_atc_code ls_atc_desc ls_indication ls_ind_meddra_lvl ls_ind_meddra_ver ls_ind_meddra_code ls_cindication ls_psur_int_birthday ls_dsur_int_birth_date ls_eu_birth_date ls_psur_reference_date ls_psur_type ls_psur_sub_freq_value ls_psur_sub_freq_unit ls_date_psur_start ls_date_psur_end ls_psur_subm_due_date
1 Medicinal Product Aceclofenac Aceclofenac Aceclofenac 1.5% w/w cream M01AB16 aceclofenac Analgesic & Anti-inflammatory
1 Medicinal Product Aceclofenac Aceclofenac Aceclofenac 100 mg tablets M01AB16 aceclofenac NSAIDS
1 Medicinal Product Aceclofenac Aceclofenac Aceclofenac 100 mg tablets M01AB16 aceclofenac Anti-inflammatory
1 Medicinal Product Aceclofenac Aceclofenac Aceclofenac 100 mg tablets M01 ANTIINFLAMMATORY AND ANTIRHEUMATIC PRODUCTS Antiinflammatory

And I am trying to format the report output of that table so I get it like this:

ord_no ls_prod_division ls_prod_area ls_prod_family_name ls_prod_family_code ls_prod_generic_name ls_brand_name ls_reference_prod ls_description ls_atc_code ls_atc_desc ls_indication ls_ind_meddra_lvl ls_ind_meddra_ver ls_ind_meddra_code ls_cindication ls_psur_int_birthday ls_dsur_int_birth_date ls_eu_birth_date ls_psur_reference_date ls_psur_type ls_psur_sub_freq_value ls_psur_sub_freq_unit ls_date_psur_start ls_date_psur_end ls_psur_subm_due_date
1 Medicinal Product Aceclofenac Aceclofenac Aceclofenac 1.5% w/w cream M01AB16 aceclofenac Analgesic & Anti-inflammatory
1 Aceclofenac 100 mg tablets M01 ANTIINFLAMMATORY AND ANTIRHEUMATIC PRODUCTS NSAIDS
1 Anti-inflammatory
1 Antiinflammatory

I am using the following code:

set colsep '|'
set trimspool on
set termout off
set echo off
set trim on
set heading on
set feedback off
set linesize 32000
set trimout on
set pagesize 50000
set underline off
col ord_no format 99999
col ls_prod_area format a200
col ls_prod_family_name format a200
col ls_prod_family_code format a200
col ls_prod_generic_name format a200
col ls_brand_name format a200
col ls_reference_prod format a200
col ls_description format a200
col ls_atc_code format a200
col ls_atc_desc format a200
col ls_indication format a200
col ls_ind_meddra_lvl format a200
col ls_ind_meddra_ver format a200
col ls_ind_meddra_code format a200
spool export.csv
break on ls_prod_area on ls_prod_family_name on ls_prod_generic_name on ls_atc_code on ls_atc_desc on ls_brand_name on ls_indication

SELECT rpad(ord_no, 200, ' ') ord_no ,rpad(ls_prod_area, 200, ' ') ls_prod_area ,rpad(ls_prod_family_name, 200, ' ') ls_prod_family_name ,rpad(ls_prod_family_code, 200, ' ') ls_prod_family_code ,rpad(ls_prod_generic_name, 200, ' ') ls_prod_generic_name ,rpad(ls_brand_name, 200, ' ') ls_brand_name ,rpad(ls_reference_prod, 200, ' ') ls_reference_prod,rpad(ls_description, 200, ' ') ls_description ,rpad(ls_atc_code, 200, ' ') ls_atc_code ,rpad(ls_atc_desc, 200, ' ') ls_atc_desc ,rpad(ls_indication, 200, ' ') ls_indication ,rpad(ls_ind_meddra_lvl, 200, ' ') ls_ind_meddra_lvl ,rpad(ls_ind_meddra_ver, 200, ' ') ls_ind_meddra_ver ,rpad(ls_ind_meddra_code, 200, ' ') ls_ind_meddra_code 
from tmp_product_family
order by ord_no, ls_brand_name,LS_ATC_CODE, LS_ATC_DESC, LS_INDICATION, LS_IND_MEDDRA_LVL, LS_IND_MEDDRA_VER, LS_IND_MEDDRA_CODE ;

And I don't have a problem with output in CMD window, but with transforming the CSV to Excel via Excel's Data From Text/CSV tool. I am putting custom delimiter which is set to '|'.

And for the first ord_no (1) first and second row that were transformed from CSV to Excel looks like this:

ORD_NO LS_PROD_AREA LS_PROD_FAMILY_NAME LS_PROD_FAMILY_CODE LS_PROD_GENERIC_NAME LS_BRAND_NAME LS_REFERENCE_PROD LS_DESCRIPTION LS_ATC_CODE LS_ATC_DESC LS_INDICATION LS_IND_MEDDRA_LVL LS_IND_MEDDRA_VER LS_IND_MEDDRA_CODE
1 Medicinal Product Aceclofenac Aceclofenac Aceclofenac 1.5% w/w cream M01AB16 aceclofenac Analgesic & Anti-inflammatory
1 Aceclofenac 100 mg tablets M01 ANTIINFLAMMATORY AND ANTIRHEUMATIC PRODUCTS Antiinflammatory

As you can see in second row all the values after the ord_no are shifted three columns to the left (e.g. Aceclofenac 100 mg tablets should be in LS_BRAND_NAME column).

Does anyone have any idea how to escape that problem.


Solution

  • As you asked about break, this is what I meant.

    An ordinary query, where all "cells" are populated with data:

    SQL> select d.dname, e.job, e.ename, e.sal
      2  from emp e join dept d on d.deptno = e.deptno
      3  order by d.dname, e.job;
    
    DNAME          JOB       ENAME             SAL
    -------------- --------- ---------- ----------
    ACCOUNTING     CLERK     MILLER           1300
    ACCOUNTING     MANAGER   CLARK            2450
    ACCOUNTING     PRESIDENT KING             5000
    RESEARCH       ANALYST   SCOTT            3000
    RESEARCH       ANALYST   FORD             3000
    RESEARCH       CLERK     ADAMS            1100
    RESEARCH       CLERK     SMITH             840
    RESEARCH       MANAGER   JONES            2975
    SALES          CLERK     JAMES             950
    SALES          MANAGER   BLAKE            2850
    SALES          SALESMAN  MARTIN           1250
    SALES          SALESMAN  WARD             1250
    SALES          SALESMAN  ALLEN            1600
    SALES          SALESMAN  TURNER           1500
    
    14 rows selected.
    

    If you put a break on e.g. department name and job, you get something that looks like result you need:

    SQL> spool stefek.csv
    SQL> break on dname on job
    SQL> select d.dname, e.job, e.ename, e.sal
      2  from emp e join dept d on d.deptno = e.deptno
      3  order by d.dname, e.job;
    
    DNAME          JOB       ENAME             SAL
    -------------- --------- ---------- ----------
    ACCOUNTING     CLERK     MILLER           1300
                   MANAGER   CLARK            2450
                   PRESIDENT KING             5000
    RESEARCH       ANALYST   SCOTT            3000
                             FORD             3000
                   CLERK     ADAMS            1100
                             SMITH             840
                   MANAGER   JONES            2975
    SALES          CLERK     JAMES             950
                   MANAGER   BLAKE            2850
                   SALESMAN  MARTIN           1250
                             WARD             1250
                             ALLEN            1600
                             TURNER           1500
    
    14 rows selected.
    
    SQL> spool off
    SQL>
    

    If you open that file in Excel, you get this:

    1. in ver. 2016, go to "Data - From text" and follow the wizard
    2. choose "Fixed width"
    3. move separator lines where necessary
    4. see the result

    enter image description here


    Connecting to SQL*Plus

    You should know username, password and database you're connecting to. For example, I'm scanning my TNSNAMES.ORA file with the mctnsping utility (written by Michel Cadot; it doesn't require Oracle client to work. You can find it on OraFAQ Forum). Or, if you have TNSPING available, use it:

    C:\Temp>mctnsping orcl
    
    McTnsping Utility by Michel Cadot: Version 2021.12.03 on 20-PRO-2022 14:09:02
    
    Copyright (c) Michel Cadot, 2016-2021. All rights reserved.
    
    Using ping version 11
    
    Used parameter files:
    C:\Users\littlefoot\Documents\sqlnet.ora
    C:\Users\littlefoot\Documents\tnsnames.ora
    
    Found tnsnames.ora entry:
    (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=db_orcl)(PORT=1521))(CONNECT_DATA=(SID=orcl)))
    
    Attempting to contact db_orcl:1521
    OK (46 msec)
    

    Now, use data you gathered; connect string is in format of @database_server:port/service_name:

    C:\Temp>sqlplus scott/tiger@db_orcl:1521/orcl
    
    SQL*Plus: Release 18.0.0.0.0 - Production on Uto Pro 20 14:09:17 2022
    Version 18.5.0.0.0
    
    Copyright (c) 1982, 2018, Oracle.  All rights reserved.
    
    
    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
    With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
    Data Mining and Real Application Testing options
       
    SQL> select * from dual;
    
    D
    -
    X
    
    SQL>