Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to export/extract Oracle Tables into Fixed-length ASCII Files 1

Status
Not open for further replies.

CraigJConrad

IS-IT--Management
Joined
May 21, 2000
Messages
66
Location
US
I am quite new to Oracle, and have searched extensively to find an answer to this problem, so I hope that I am not asking something too obvious to others.

We have a client running Oracle for an application being sunset. In order to accomodate this, we need to perform extensive processing on the final data using Cobol programs that run on a different server (ie, these programs can not have access to the Oracle database directly).

Therefore, we need to extract (export?) data from the Oracle tables into a flat file to be shipped to the server for processing by Cobol. The flat files must be in "traditional" Cobol FD format -- i.e. each field is fixed-length (no CSV). Of course, the text fields must be in ASCII (not binary) and ideally the numeric fields would be ASCII (not COMP) as well.

What is the best approach to do this? Purchasing of a reasonably-priced tool is an acceptable solution.

Thanks in advance for any assistance.

Craig
 
Crg,

Before I became an Oracle aficionado, my California license plate was "CPN COBOL". I received a lot of ribbing from my Oracle colleagues about being Captain COBOL until I relented and changed my plate to "DATA MAN". So, I know what challenges you are dealing with.

Following, then, is a script I wrote for you to produce fixed-length output fields, left-zero padded or right-space padded where appropriate.

Notes:
1) For the sake of your data security, this script presently runs only for tables that the current user owns (i.e., that appear in USER_TABLES).
2) Date fields appear in "YYYYMMDD" format, but you can modify the code to fit alternate formats, if you choose. NULL dates appear as "00000000".
3) This script does not handle Oracle's deprecated LONG columns
4) This script does handle all numeric columns, CHAR, VARCHAR/VARCHAR2, DATE, and CLOB. Any other types of columns result in the output, "'Datatype ('<offending data type>') for column '<column_name>' not supported."
5) CLOB columns will be a fixed length equal to the longest CLOB expression in the table.
6) CLOB columns with NULL values depend upon this tiny user-defined function:
Code:
create or replace function null_clob return clob is begin return ' '; end
/
7) The widths of the fixed-length columns default from column definitions in your Oracle data dictionary. If you wish to change the widths from the generated defaults, you may edit the script that my script generates ("temp.sql") before running the script. You will want to comment out the automatic running of the "temp.sql" script ("REM @temp") if you choose to edit the script before it runs.

Section 1 -- "GenFixed.sql" script:
Code:
REM **************************************************************
REM David L. Hunt (file author) distributes this and other 
REM files/scripts for educational purposes only, to illustrate the 
REM use or application of various computing techniques. Neither the 
REM author nor Dasages, LLC, makes any warranty regarding this 
REM script's fitness for any industrial application or purpose nor is 
REM there any claim that this or any similarly-distributed scripts 
REM are error free or should be used for any purpose other than
REM illustration.
REM
REM Free use of this script requires this disclaimer/disclosure 
REM remaining with the script.
REM
REM Send questions or comments to "dave@dasages.com"
REM **************************************************************
set echo off
accept x prompt "Enter the table to fix length: "
accept y prompt "Enter the flat file to write: "
prompt
prompt Following output is generated script that writes text output from table "&x"
prompt 
set verify off
set feedback off
set heading off
set pagesize 0
set linesize 32767
set trimout on
set trimspool on
spool temp.sql
prompt set echo off
prompt set feedback off
prompt set heading off
prompt set long 32767
prompt set longchunksize 32767
prompt set lines 32767
prompt set trimspool on
prompt set pagesize 0
prompt spool &y
select decode(rownum,1,'Select ','||')|| -- Displays "SELECT" in front of 1st line, "||" in front of any other line
  CASE when substr(data_type,1,4) = 'DATE' then -- checks for DATE column
            'nvl(to_char('||column_name||',''YYYYMMDD''),''00000000'')' -- codes DATE-column output/ null = all zeroes
       when substr(data_type,1,4) = 'LONG' then -- checks for LONG column
            'rpad('||column_name -- left justifies LONG column
            ||',(select max(length('||column_name||')) from &x))' -- creates code to "try" to determine longest LONG
            -- but this code will fail when one attempts to execute the 'temp.sql' generated script.
       when substr(data_type,1,4) = 'CLOB' then -- checks for CLOB column
            'rpad(nvl('||column_name||',null_clob)' -- left justifies CLOB column
            ||',(select max(length('||column_name||')) from &x))' -- returns length of longest CLOB for fixed-length
       when substr(data_type,1,4) = 'VARC' then -- checks for VARCHAR2 column
            'rpad(nvl('||column_name||','' '')' -- left justifies VARCHAR2 column
            ||','||ltrim(to_char(data_length,'9999'))||')' -- hard codes length of VARCHAR2 column
       when substr(data_type,1,4) = 'CHAR' then -- checks for fixed-length CHAR column
            'rpad(nvl('||column_name||','' '')' -- left justifies fixed-length CHAR column
            ||','||ltrim(to_char(data_length,'9999'))||')' -- hard codes length of VARCHAR2 column
       when substr(data_type,1,4) = 'NUMB' and data_scale is not null and data_precision is not null then
            -- checks for NUMBER column and ensures explicit precision and scale
            'lpad(substr(nvl('||column_name||',0)' -- raw numeric source column
                          ||'* power(10,'||data_scale||')' -- multiplies raw numeric value by a power of 10
                                                           -- equalling "scale" for decimal alignment
                        ||',1,' -- substr decimal-aligned string begining with leftmost character (position 1)
                        ||data_precision||')' -- specifies maximum length of substring of decimal-aligned column value
                  ||','||data_precision -- specifies fixed length of resulting left-zero-padded numeric column
                  ||',''0'')' -- specifies left padding as zeroes
       when substr(data_type,1,4) = 'NUMB' and data_scale is null and data_precision is null then
            -- checks for NUMBER created without explicit precision and scale, i.e. "NUMBER" instead of "NUMBER (x,y)"
            'lpad(substr(nvl('||column_name||',0)' -- raw numeric source column
                          ||'* power(10,' -- multiplied by a power of 10 equalling "scale" (calculated below)
                                     ||'(select max(length(substr('||column_name -- specify numeric column for decimal check
                                                                  ||',instr('||column_name||',''.'')' -- locate decimal
                                                                  ||'+1' -- then begin string just beyond decimal
                                                             ||')' -- end substr from behind decimal
                                                      ||')' -- end determining length of post-decimal string
                                                ||')' -- end finding greatest post-decimal string
                                       ||'from &x' -- specifies target table to subquery
                                    ||')' -- end sub-query returning longest post-decimal magnitude
                                ||')' -- end of POWER function that specifies number of decimal point-alignment digits
                      ||',1,' -- substr decimal-aligned string begining with leftmost character (position 1)
                   -- ||chr(10) -- line-feed to avoid off-the-page code appearance
                   -- for a total substring length calculated by sum of maximum pre-decimal digits
                   -- plus max post-decimal digits:
                      ||'(Select max(length(trunc('||column_name||')' -- produce pre-decimal string
                                        ||')' -- end determining length of pre-decimal digits
                                 ||')' -- end finding longest set of pre-decimal digits
                         ||'from &x'-- specifies target table to subquery
                      ||')' -- end sub-query that returns longest pre-decimal length
                      ||'+' -- plus longest post-decimal length (following)
                      ||'(Select max(length(substr('||column_name -- specify numeric column for post-decimal-length check
                                                    ||',instr('||Column_name||',''.'')' -- locate decimal in numeric value
                                                    ||'+1' -- then begin string just beyond decimal
                                               ||')' -- end substr from behind decimal string
                                        ||')' -- end determining length of post-decimal string
                                 ||')' -- end determining greatest length of post-decimal string
                         ||'from &x' -- specifies target table to subquery
                      ||')' -- end sub-query that returns longest post-decimal length
                      ||')' -- end of substr of decimal-aligned, decimal-removed value
               ||',' -- ends argument 1 of LPAD
            -- ||chr(10) -- line-feed to avoid off-the-page code appearance
            -- following section reproduces "length" argument of LPAD. As above, the LPAD length results
            -- from sum of maximum pre-decimal digits plus max post-decimal digits:
                      ||'(Select max(length(trunc('||column_name||')' -- produce pre-decimal string
                                        ||')' -- end determining length of pre-decimal digits
                                 ||')' -- end finding longest set of pre-decimal digits
                         ||'from &x'-- specifies target table to subquery
                      ||')' -- end sub-query that returns longest pre-decimal length
                      ||'+' -- plus longest post-decimal length (following)
                      ||'(Select max(length(substr('||column_name -- specify numeric column for post-decimal-length check
                                                    ||',instr('||Column_name||',''.'')' -- locate decimal in numeric value
                                                    ||'+1' -- then begin string just beyond decimal
                                               ||')' -- end substr from behind decimal string
                                        ||')' -- end determining length of post-decimal string
                                 ||')' -- end determining greatest length of post-decimal string
                         ||'from &x' -- specifies target table to subquery
                      ||')' -- end sub-query that returns longest post-decimal length
               ||',''0'')' -- LPAD's left-fill character definition
       else
            'Datatype ("'||data_type||'") for column "'||column_name||'" not supported.'
   end fixed_lengths
  from user_tab_columns
  where table_name = upper('&x');
prompt from &x
prompt /
prompt spool off
prompt set feedback on
prompt set heading on
prompt set pagesize 20
spool off
prompt
prompt Following is text output written to file "&y"
prompt
@temp
set echo off
prompt
prompt Output file = "&y"
prompt
REM***************************************************************************************************************************

Section 2 -- Format of a sample table that includes NUMBER, NUMBER(7,2), CHAR, VARCHAR2, DATE, and CLOB column definitions:
Code:
SQL> desc test2
 Name              Null?    Type
 ----------------- -------- ------------
 A                          NUMBER(7,2)
 B                          CHAR(14)
 C                          VARCHAR2(20)
 D                          DATE
 E                          CLOB
 F                          NUMBER
Section 3 -- Sample data in the test2 table:
Code:
SQL> select * from test2;

              A B              C                  D         E                                                             F
--------------- -------------- ------------------ --------- ----------------------------------------------- ---------------
            1.5 14 chrs. long  18 chrs. long max. 08-MAY-05 CLOB expression; fixed length = longest string.
             27 7 chars.       abc                07-MAY-05 abc                                                    12345.35
             45
       99999.99 abc            abc                03-MAY-05 This is a short CLOB                            1234567.1234567

4 rows selected.
Section 4: Sample invocation of the "GenFixed.sql" script that generates fixed-length records from the "test2" table:
Code:
SQL> @genfixed
Enter the table to fix length: test2
Enter the flat file to write: test2.txt

Following output is generated script that writes text output from table "test2"

set echo off
set feedback off
set heading off
set long 32767
set longchunksize 32767
set lines 32767
set trimspool on
set pagesize 0
spool test2.txt
Select lpad(substr(nvl(A,0)* power(10,2),1,7),7,'0')
||rpad(nvl(B,' '),14)
||rpad(nvl(C,' '),20)
||nvl(to_char(D,'YYYYMMDD'),'00000000')
||rpad(nvl(E,null_clob),(select max(length(E)) from test2))
||lpad(substr(nvl(F,0)* power(10,(select max(length(substr(F,instr(F,'.')+1)))from test2)),1,
(Select max(length(trunc(F)))from test2)+
(Select max(length(substr(F,instr(F,'.')+1)))from test2)),(Select max(length(trunc(F)))from test2)+(Select max(length(substr(F,instr(F,'.')+1)))from test2),'0')from test2
/
spool off
set feedback on
set heading on
set pagesize 20

Following is text output written to file "test2.txt"

000015014 chrs. long 18 chrs. long max.  20050508CLOB expression; fixed length = longest string.00000000000000000
00027007 chars.      abc                 20050507abc                                            00012345350000000
0004500                                  00000000                                               00000000000000000
9999999abc           abc                 20050503This is a short CLOB                           01234567123456700
0000000wxyz          wxyz                20050329wxyz                                           12345678000000000
0000000wxyz          wxyz                20050329wxyz                                           00000000123456789

Output file = "test2.txt"
Let me know, Crg, if this does what you wanted.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)

Do you use Oracle and live or work in Utah, USA?
Then click here to join Utah Oracle Users Group on Tek-Tips.
 
One additional note of importance about the above "GenFixed.sql" script: It does not presently deal with negative numbers since your specifications did not include how you wanted negative values to appear in your fixed-length output. Back when I was "CPN COBOL", negative values appeared with a negative ("-") overpunch on the right most character. [Of course that shows how old I am...overpunching was on keypunch cards.] I'm certain a similar effect could occur in the script, but before I spend any time building the "wrong" solution for you, I am hoping for guidance from you.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)

Do you use Oracle and live or work in Utah, USA?
Then click here to join Utah Oracle Users Group on Tek-Tips.
 
**** WOW!! ****

I am so very impressed and grateful for such a quick and thorough response!

What you did looks PERFECT! (stars to you)

Regarding negative numbers, I haven't yet seen all of the schema/data (there are 1100+ tables), so I don't know how many fields could be negative. You are correct, though, that fields that could contain negative numbers would have to be "signed" fields in Cobol and would require the overpunch (ugh!), resulting in "J" thru "R" for negative 1 thru 9). Is that difficult to do (any guidance appreciated)?

Again, my deepest gratitude ...

Craig
 
Yes, Craig, I can certainly build a modification for you that deals with negative values. Please confirm explicitly how you want negative numbers to appear, and I shall make the change to the code.

Keep in mind that as a result of producing "fixed-length" values, the code may add insignificant trailing zeroes behind the decimal point. For example, in the sample data for column "A", above, the database-stored values "1.5" and "27" became "0000150" and "0002700", respectively, to yield decimal alignment and a fixed length. In each case, an overpunch over the rightmost characters would appear over the rightmost "0"s, not over the "5" and the "7", respectively.

So, once you confirm how you want me to handle negatives, I'm happy to implement that adjustment with an updated code posting.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)

Do you use Oracle and live or work in Utah, USA?
Then click here to join Utah Oracle Users Group on Tek-Tips.
 
Mufasa (Dave),

An "overstrike" of the final digit is, indeed, what is required for Cobol signed ("S" PIC fields). When the number is positive, the last digit would be changed from its "0" thru "9" into "{ABCDEFGHI", respectively. When the number is negative, the last digit would be changed from its "0" thru "9" into "}JKLMNOPQR", respectively.

Thank you very much!

Craig
 
Mufasa (Dave),

If the right-most digit is 0, and the number is positive, then it would be a "{"; if negative, then "}".

Thanks, Craig
 
Silly me...I meant to say, "What if the value of the entire number is zero?"...which makes the number neither positive nor negative; do you still want a right-most over punch as though it is positive or no overpunch at all?

BTW, you're up late. If you can wait up for a few more minutes, I should have a solution for you.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)

Do you use Oracle and live or work in Utah, USA?
Then click here to join Utah Oracle Users Group on Tek-Tips.
 
Mufasa,

That's a good question. I can't recall for sure what a neutral (ie, "0") storage representation is for signed, but I *thing* that it is a "positive 0", thereby it would be represented as "{".

Does that make sense?

Craig
 
Craig, did you leave me hangin' here? [banghead] I got back to you within 3 minutes of your earlier post, but it appears that you must have gone to bed right after you hit the [Submit Post] button. I would love to deliver "the final solution" to you tonight, but it would be a little useless if I choose wrong on the "NULL numbers" issue.

I'm getting sleepy and plan to turn in now, but I'll check again in the morning for guidance around 9:00 a.m. MDT.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)

Do you use Oracle and live or work in Utah, USA?
Then click here to join Utah Oracle Users Group on Tek-Tips.
 
I'm still here (- sorry!)... I was actually thinking about your question, as it raised another. I was trying to understand what is best regarding nullable fields in general, as well as lengths for VARCHAR fields.

I am thinking that a preceeding length field for VARCHARs would be ideal, and a preceding null indicator (e.g. "0" for not-null and "1" for null, or something similar). If a field is both nullable and a VARCHAR, should both the length and null indicator appear and, if so, in what order? Your advise would be welcome (if no opinion, then I would suggest null first, then length).

For null character fields, the actual field should be blanks; for null numbers, the actual field should be zero.

I really feel like I'm taking undue advantage of you, but I appreciate your help tremendously.

Craig
 
Craig said:
For null character fields, the actual field should be blanks; for null numbers, the actual field should be zero.
For COBOL (due to COBOL's relatively low IQ), your specification above, is correct. What I can do for you (if you want...and I need your confirmation on this) is to

1) make NULL numerics unsigned all zeroes;
2) make explicity ZERO numerics all zeroes, but overpunch the rightmost character with a positive overpunch.

In COBOL (at least back in the "old days" when I last used COBOL in 1988), there was no such thing as a NULL character value...only all spaces.

So, do the above assertions meet with your approval? If not, please adjust as needed.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)

Do you use Oracle and live or work in Utah, USA?
Then click here to join Utah Oracle Users Group on Tek-Tips.
 
Mufasa,

This might work, but I am concerned that, once I define a field as "S9(4)", that Cobol might choke on processing a field that does not have signed overpunch. I can't be sure until I test this (I could do so Wednesday), unless you think that it will read okay. If not, NULL numerics should still get the zero overpunch. Could a preceeding null indicator be supported?

Thanks, Craig
 
Craig,

I'll make nulls appear as explicit Zeroes appear. I highly discourage your using "preceeding null indicators" since they would cause a data contrivance for COBOL to have to deal with programmatically.

I'll have a solution for you in a few minutes based upon what I've confirmed here and in the previous posts. Will you still be up?

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)

Do you use Oracle and live or work in Utah, USA?
Then click here to join Utah Oracle Users Group on Tek-Tips.
 
Mufasa,

I'm still up. I, unfortunately, am managing a project that has resources in Singapore and the US. As Singapore is exactly 12 hours ahead of my time zone, that leaves me working around-the-clock (sleep when I can get away with it), whether I am here in US, or away in Singapore.

Craig
 
Here, then, is revised code. To cause the least amount of disruption to the earlier script (GenFixed.sql), The only change to the script (below) appears in bold type...it is the enclosure of our previous results (for both numeric scenarios) within a new user-defined function named "COBOL_SIGN". Therefore, to put things in cronological order, this new function appears first. It is what causes the results to be overpunched with a positive or negative indicator as you have specified for both explicit values and for NULL numeric expressions:

Section 1 -- COBOL_SIGN function:
Code:
create or replace function cobol_sign (val number, str varchar2) return varchar2 is
    sign_val    number;
    last_chr    varchar2(1);
    punched_chr varchar2(1);
    return_str  varchar2(100);
begin
    sign_val  := sign(val);
    last_chr  := substr(str,-1);
    case when sign_val = -1 then
             punched_chr := translate(last_chr,'0123456789','}JKLMNOPQR');
             return_str  := substr(str,1,length(str)-1)||punched_chr;
         when sign_val in (0,1) or sign_val is null then
             punched_chr := translate(last_chr,'0123456789','{ABCDEFGHI');
             return_str  := substr(str,1,length(str)-1)||punched_chr;
    end case;
    return return_str;
end;
/

Function created.

Section 2 -- Latest version of "GenFixed.sql", which includes, where appropriate (emboldened) new code to handle COBOL overpunches for numeric expressions:
Code:
REM **************************************************************
REM David L. Hunt (file author) distributes this and other 
REM files/scripts for educational purposes only, to illustrate the 
REM use or application of various computing techniques. Neither the 
REM author nor Dasages, LLC, makes any warranty regarding this 
REM script's fitness for any industrial application or purpose nor is 
REM there any claim that this or any similarly-distributed scripts 
REM are error free or should be used for any purpose other than
REM illustration.
REM
REM Free use of this script requires this disclaimer/disclosure 
REM remaining with the script.
REM
REM Send questions or comments to "dave@dasages.com"
REM **************************************************************
set echo off
accept x prompt "Enter the table to fix length: "
accept y prompt "Enter the flat file to write: "
prompt
prompt Following output is generated script that writes text output from table "&x"
prompt 
set verify off
set feedback off
set heading off
set pagesize 0
set linesize 32767
set trimout on
set trimspool on
spool temp.sql
prompt set echo off
prompt set feedback off
prompt set heading off
prompt set long 32767
prompt set longchunksize 32767
prompt set lines 32767
prompt set trimspool on
prompt set pagesize 0
prompt spool &y
select decode(rownum,1,'Select ','||')|| -- Displays "SELECT" in front of 1st line, "||" in front of any other line
  CASE when substr(data_type,1,4) = 'DATE' then -- checks for DATE column
            'nvl(to_char('||column_name||',''YYYYMMDD''),''00000000'')' -- codes DATE-column output/ null = all zeroes
       when substr(data_type,1,4) = 'LONG' then -- checks for LONG column
            'rpad('||column_name -- left justifies LONG column
            ||',(select max(length('||column_name||')) from &x))' -- creates code to "try" to determine longest LONG
            -- but this code will fail when one attempts to execute the 'temp.sql' generated script.
       when substr(data_type,1,4) = 'CLOB' then -- checks for CLOB column
            'rpad(nvl('||column_name||',null_clob)' -- left justifies CLOB column
            ||',(select max(length('||column_name||')) from &x))' -- returns length of longest CLOB for fixed-length
       when substr(data_type,1,4) = 'VARC' then -- checks for VARCHAR2 column
            'rpad(nvl('||column_name||','' '')' -- left justifies VARCHAR2 column
            ||','||ltrim(to_char(data_length,'9999'))||')' -- hard codes length of VARCHAR2 column
       when substr(data_type,1,4) = 'CHAR' then -- checks for fixed-length CHAR column
            'rpad(nvl('||column_name||','' '')' -- left justifies fixed-length CHAR column
            ||','||ltrim(to_char(data_length,'9999'))||')' -- hard codes length of VARCHAR2 column
       when substr(data_type,1,4) = 'NUMB' and data_scale is not null and data_precision is not null then
            -- checks for NUMBER column and ensures explicit precision and scale
            [b]'cobol_sign('||column_name||','|| -- produces a value with overpunched rightmost chr. for COBOL sign handling[/b]
            'lpad(substr(nvl('||column_name||',0)' -- raw numeric source column
                          ||'* power(10,'||data_scale||')' -- multiplies raw numeric value by a power of 10
                                                           -- equalling "scale" for decimal alignment
                        ||',1,' -- substr decimal-aligned string begining with leftmost character (position 1)
                        ||data_precision||')' -- specifies maximum length of substring of decimal-aligned column value
                  ||','||data_precision -- specifies fixed length of resulting left-zero-padded numeric column
                  ||',''0'')' -- specifies left padding as zeroes
                  [b]||')' -- closes "COBOL_SIGN" function[/b]
       when substr(data_type,1,4) = 'NUMB' and data_scale is null and data_precision is null then
            -- checks for NUMBER created without explicit precision and scale, i.e. "NUMBER" instead of "NUMBER (x,y)"
            [b]'cobol_sign('||column_name||','|| -- produces a value with overpunched rightmost chr. for COBOL sign handling[/b]
            'lpad(substr(nvl('||column_name||',0)' -- raw numeric source column
                          ||'* power(10,' -- multiplied by a power of 10 equalling "scale" (calculated below)
                                     ||'(select max(length(substr('||column_name -- specify numeric column for decimal check
                                                                  ||',instr('||column_name||',''.'')' -- locate decimal
                                                                  ||'+1' -- then begin string just beyond decimal
                                                             ||')' -- end substr from behind decimal
                                                      ||')' -- end determining length of post-decimal string
                                                ||')' -- end finding greatest post-decimal string
                                       ||'from &x' -- specifies target table to subquery
                                    ||')' -- end sub-query returning longest post-decimal magnitude
                                ||')' -- end of POWER function that specifies number of decimal point-alignment digits
                      ||',1,' -- substr decimal-aligned string begining with leftmost character (position 1)
                   -- for a total substring length calculated by sum of maximum pre-decimal digits
                   -- plus max post-decimal digits:
                      ||'(Select max(length(trunc('||column_name||')' -- produce pre-decimal string
                                        ||')' -- end determining length of pre-decimal digits
                                 ||')' -- end finding longest set of pre-decimal digits
                         ||'from &x'-- specifies target table to subquery
                      ||')' -- end sub-query that returns longest pre-decimal length
                      ||'+' -- plus longest post-decimal length (following)
                      ||'(Select max(length(substr('||column_name -- specify numeric column for post-decimal-length check
                                                    ||',instr('||Column_name||',''.'')' -- locate decimal in numeric value
                                                    ||'+1' -- then begin string just beyond decimal
                                               ||')' -- end substr from behind decimal string
                                        ||')' -- end determining length of post-decimal string
                                 ||')' -- end determining greatest length of post-decimal string
                         ||'from &x' -- specifies target table to subquery
                      ||')' -- end sub-query that returns longest post-decimal length
                      ||')' -- end of substr of decimal-aligned, decimal-removed value
               ||',' -- ends argument 1 of LPAD
            -- following section reproduces "length" argument of LPAD. As above, the LPAD length results
            -- from sum of maximum pre-decimal digits plus max post-decimal digits:
                      ||'(Select max(length(trunc('||column_name||')' -- produce pre-decimal string
                                        ||')' -- end determining length of pre-decimal digits
                                 ||')' -- end finding longest set of pre-decimal digits
                         ||'from &x'-- specifies target table to subquery
                      ||')' -- end sub-query that returns longest pre-decimal length
                      ||'+' -- plus longest post-decimal length (following)
                      ||'(Select max(length(substr('||column_name -- specify numeric column for post-decimal-length check
                                                    ||',instr('||Column_name||',''.'')' -- locate decimal in numeric value
                                                    ||'+1' -- then begin string just beyond decimal
                                               ||')' -- end substr from behind decimal string
                                        ||')' -- end determining length of post-decimal string
                                 ||')' -- end determining greatest length of post-decimal string
                         ||'from &x' -- specifies target table to subquery
                      ||')' -- end sub-query that returns longest post-decimal length
               ||',''0'')' -- LPAD's left-fill character definition
               [b]||')' -- closes "COBOL_SIGN" function[/b]
       else
            'Datatype ("'||data_type||'") for column "'||column_name||'" not supported.'
   end fixed_lengths
  from user_tab_columns
  where table_name = upper('&x');
prompt from &x
prompt /
prompt spool off
prompt set feedback on
prompt set heading on
prompt set pagesize 20
spool off
prompt
prompt Following is text output written to file "&y"
prompt
@temp
set echo off
prompt
prompt Output file = "&y"
prompt
REM**********************************************************************************************************************************

Section 3 -- Updated values in Test2 table:
Code:
SQL> select * from test2;

                   A B              C                  D         E                                                                  F
-------------------- -------------- ------------------ --------- ----------------------------------------------- --------------------
                 1.5 14 chrs. long  18 chrs. long max. 08-MAY-05 CLOB expression; fixed length = longest string.
                  27 7 chars.       abc                07-MAY-05 abc                                                         12345.35
                  45
            99999.99 abc            abc                03-MAY-05 This is a short CLOB                                 1234567.1234567
                     wxyz           wxyz               29-MAR-05 wxyz                                                        12345678
                   0 wxyz           wxyz               29-MAR-05 wxyz                                                      .123456789

Section 4 -- Invocation of "GenFixed.sql" with overpunches for numeric expressions:
Code:
SQL> @genfixed
Enter the table to fix length: test2
Enter the flat file to write: temp.txt

Following output is generated script that writes text output from table "test2"

set echo off
set feedback off
set heading off
set long 32767
set longchunksize 32767
set lines 32767
set trimspool on
set pagesize 0
spool temp.txt
Select cobol_sign(A,lpad(substr(nvl(A,0)* power(10,2),1,7),7,'0'))
||rpad(nvl(B,' '),14)
||rpad(nvl(C,' '),20)
||nvl(to_char(D,'YYYYMMDD'),'00000000')
||rpad(nvl(E,null_clob),(select max(length(E)) from test2))
||cobol_sign(F,lpad(substr(nvl(F,0)* power(10,(select max(length(substr(F,instr(F,'.')+1)))from test2)),1,
(Select max(length(trunc(F)))from test2)+
(Select max(length(substr(F,instr(F,'.')+1)))from test2)),(Select max(length(trunc(F)))from test2)+
(Select max(length(substr(F,instr(F,'.')+1)))from test))
from test2
/
spool off
set feedback on
set heading on
set pagesize 20

Following is text output written to file "temp.txt"

000015{14 chrs. long 18 chrs. long max.  20050508CLOB expression; fixed length = longest string.0000000000000000{
000270{7 chars.      abc                 20050507abc                                            0001234535000000{
000450{                                  00000000                                               0000000000000000{
999999Iabc           abc                 20050503This is a short CLOB                           0123456712345670{
000000{wxyz          wxyz                20050329wxyz                                           1234567800000000{
000000{wxyz          wxyz                20050329wxyz                                           0000000012345678I

Output file = "temp.txt"
Let me know if this does what you wanted.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)

Do you use Oracle and live or work in Utah, USA?
Then click here to join Utah Oracle Users Group on Tek-Tips.
 
Mufasa,

By the way, can you elaborate on the issue with adding a one-byte field preceeding a NULLABLE field, in which an ASCII character would indicate whether the specific value is null or not? Wouldn't this merely be a field that the Cobol program *could* check, if it cared, but ignore otherwise? It wouldn't be part of the data value field itself.

Just curious ... Craig
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top