tags:

views:

4230

answers:

2

By default sqlplus truncates column names to the length of the underlying data type. Many of the column names in our database are prefixed by the table name, and therefore look identical when truncated.

I need to specify select * queries to remote DBAs in a locked down production environment, and drag back spooled results for diagnosis. There are too many columns to specify individual column formatting. Does sqlplus offer any option to uniformly defeat column name truncation?

(I am using SET MARKUP HTML ON, though I could use some other modality, csv, etc. as long as it yields unabbreviated output.)

A: 

I don't think sqlplus offers the functionality you are requesting. You might be able to automate the formatting, using some sort of scripting language such as Perl or Python. In other words, query the ALL_TAB_COLS view for the schema and table, and then create the script dynamically with a format column attribute. This will only work, of course, if you have permission to query the ALL_TAB_COLS view (or some other equivalent).

This is a quick proof-of-concept I threw together:

#!/usr/bin/python

import sys
import cx_Oracle

response=raw_input("Enter schema.table_name:  ")
(schema, table) = response.split('.')
schema = schema.upper()
table = table.upper()
sqlstr = """select column_name,
                   data_type,
                   data_length
              from all_tab_cols
             where owner      = '%s'
               and table_name = '%s'""" % ( schema, table )

## open a connection to databases...
try:
    oracle = cx_Oracle.Connection( oracleLogin )
    oracle_cursor = oracle.cursor()

except cx_Oracle.DatabaseError, exc:
    print "Cannot connect to Oracle database as", oracleLogin
    print "Oracle Error %d:  %s" % ( exc.args[0].code, exc.args[0].message )
    sys.exit(1)

try:
    oracle_cursor.execute( sqlstr )

    # fetch resultset from cursor
    for column_name, data_type, data_length in oracle_cursor.fetchmany(256):
        data_length = data_length + 0
        if data_length < len(column_name):
            if data_type == "CHAR" or data_type == "VARCHAR2":
                print "column %s format a%d" % ( column_name.upper(), len(column_name) )
            else:
                print "-- Handle %s, %s, %d" % (column_name, data_type, data_length)

except cx_Oracle.DatabaseError, e:
    print "[Oracle Error %d: %s]:  %s" % (e.args[0].code, e.args[0].message, sqlstr)
    sys.exit(1)

try:
    oracle_cursor.close()
    oracle.close()
except cx_Oracle.DatabaseError, exc:
    print "Warning: Oracle Error %d:  %s" % ( exc.args[0].code, exc.args[0].message )

print "select *"
print "from %s.%s" % ( schema, table )
m0j0
Thanks for the python code, unfortunately our customer strictly prohibits installation of any other software in their production environment. Not even grep or tail. Ugh. So it's sqlplus or bust.
Chris Noe
+1  A: 

One thing you can try is to dynamically generate "column x format a20" commands. Something like the following:

set termout off
set feedback off

spool t1.sql
select 'column ' || column_name || ' format a' || data_length
from all_tab_cols
where table_name='YOUR_TABLE'
/
spool off

@t1.sql
set pagesize 24
set heading on
spool result.txt
select * 
from  YOUR_TABLE;
and   rownum < 30;
spool off

Note that this sample will only work with VARCHAR2. You would need to add decode for example to change the generated "column" command for DATEs or NUMBERs.

UPDATE: It turns out the original SQL doesn't really change the behaviour of the SQL*Plus. The only thing I could think of is to rename the field names to one character values A, B, C, etc.. in the following way:

select 'column ' || column_name ||
       ' heading "' ||
       chr(ascii('A') - 1 + column_id) ||
       '"'
from all_tab_cols
where table_name='YOUR_TAB_NAME'

It will generate the output similar to:

column DEPT_NO heading "A"
column NAME heading "B"
column SUPERVIS_ID heading "C"
column ADD_DATE heading "D"
column REPORT_TYPE heading "E"
IK
Hmm, a bit heavy handed, but I guess that could work. Except I don't think you mean data_length. Wouldn't that just be the length of the underlying data type, and therefore result in the default sqlplus behavior? Is there maybe a string length operation that could be applied to the column name?
Chris Noe
Chris, you are correct. I just realized that it only affects the format of the values and not the format of the heading. Select statement for a bit different approach is in the post's update.
IK
So I would end up showing me columns labeled A, B, C, etc... But my goal is for the output to show the original column names, untruncated, so that I can tell which column is which.
Chris Noe
Got it, this works: select 'column ' || column_name || ' format a' || greatest(length(column_name), data_length) from all_tab_cols where table_name='YOUR_TAB_NAME' If you'll edit this in, I'll mark your answer accepted. Thanks!
Chris Noe
Er, the code in my previous comment almost works. But data_length is not the same as formatted output length, so dates for example don't get enough space when the column name is shorter than 9 characters, eg: 11-DEC-08. Not sure how that should be handled...
Chris Noe