Предотвращение усечения sqlplus имен столбцов без индивидуального форматирования столбцов - PullRequest
6 голосов
/ 09 декабря 2008

По умолчанию sqlplus усекает имена столбцов до длины базового типа данных. Многие имена столбцов в нашей базе данных начинаются с префикса имени таблицы и поэтому при усечении выглядят одинаково.

Мне нужно указать запросы select * для удаленных администраторов баз данных в заблокированной производственной среде и перетащить буферизованные результаты для диагностики. Слишком много столбцов, чтобы указать форматирование отдельных столбцов. Предоставляет ли sqlplus какую-либо опцию для равномерного устранения усечения имен столбцов?

(Я использую SET MARKUP HTML ON, хотя я мог бы использовать некоторые другие модальности, csv и т. Д., Если он дает несокращенный вывод.)

Ответы [ 6 ]

3 голосов
/ 10 декабря 2008

Одна вещь, которую вы можете попробовать, это динамически генерировать команды "column x format a20". Примерно так:

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

Обратите внимание, что этот пример будет работать только с VARCHAR2. Например, вам нужно добавить декодирование, чтобы изменить сгенерированную команду «столбец» для DATE или NUMBER.

ОБНОВЛЕНИЕ: Оказывается, оригинальный SQL на самом деле не меняет поведение SQL * Plus. Единственное, о чем я мог подумать, это переименовать имена полей в однозначные значения A, B, C и т. Д. Следующим образом:

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

Будет сгенерирован вывод, похожий на:

column DEPT_NO heading "A"
column NAME heading "B"
column SUPERVIS_ID heading "C"
column ADD_DATE heading "D"
column REPORT_TYPE heading "E"
2 голосов
/ 26 июня 2014

Ни одно из предложенных решений не работает для отображения оригинальных имен столбцов, поэтому я не уверен, почему люди голосуют за них ... У меня есть "хак", который работает для исходного запроса, но я действительно не это нравится ... То есть вы фактически добавляете или добавляете префикс к запросу для каждого столбца, чтобы они всегда были достаточно длинными для заголовка столбца. Если вы находитесь в режиме HTML, как это показано на постере, небольшой лишний интервал наносит небольшой вред ... Конечно, это замедлит ваш запрос abit ...

, например

SET ECHO OFF
SET PAGESIZE 32766
SET LINESIZE 32766
SET NUMW 20
SET VERIFY OFF
SET TERM OFF
SET UNDERLINE OFF
SET MARKUP HTML ON
SET PREFORMAT ON
SET WORD_WRAP ON
SET WRAP ON
SET ENTMAP ON
spool '/tmp/Example.html'
select 
   (s.ID||'                  ') AS ID,
   (s.ORDER_ID||'                  ') AS ORDER_ID,
   (s.ORDER_NUMBER||'                  ') AS ORDER_NUMBER,
   (s.CONTRACT_ID||'                  ') AS CONTRACT_ID,
   (s.CONTRACT_NUMBER||'                  ') AS CONTRACT_NUMBER,
   (s.CONTRACT_START_DATE||'                  ') AS CONTRACT_START_DATE,
   (s.CONTRACT_END_DATE||'                  ') AS CONTRACT_END_DATE,
   (s.CURRENCY_ISO_CODE||'                  ') AS CURRENCY_ISO_CODE,
from Example s
order  by s.order_number, s.contract_number;
spool off;

Конечно, вы могли бы написать хранимую процедуру, чтобы сделать что-то лучше, но на самом деле это кажется излишним для этого простого сценария.

Это также не соответствует первоначальному запросу постеров. В том, что это требует, вручную перечисляя по столбцам и не используя select *. Но, по крайней мере, это решение работает, когда вы готовы детализировать поля.

Однако, поскольку на самом деле нет проблем с наличием слишком длинных полей в HTML, существует довольно простой способ исправить решение Криса, чтобы оно работало в этом примере. То есть просто выберите максимальное значение, которое позволит оракул. К сожалению, это все равно не будет работать для КАЖДОГО поля каждой таблицы, если вы явно не добавите форматирование для каждого типа данных. Это решение также не будет работать для объединений, поскольку разные таблицы могут использовать одно и то же имя столбца, но разные типы данных.

SET ECHO OFF
SET TERMOUT OFF
SET FEEDBACK OFF
SET PAGESIZE 32766
SET LINESIZE 32766
SET MARKUP HTML OFF
SET HEADING OFF

spool /tmp/columns_EXAMPLE.sql
select 'column ' || column_name || ' format A32766' 
from all_tab_cols
where data_type = 'VARCHAR2' and table_name = 'EXAMPLE'
/
spool off

SET HEADING ON
SET NUMW 40
SET VERIFY OFF
SET TERM OFF
SET UNDERLINE OFF
SET MARKUP HTML ON
SET PREFORMAT ON
SET WORD_WRAP ON
SET WRAP ON
SET ENTMAP ON
@/tmp/columns_EXAMPLE.sql
spool '/tmp/Example.html'
select *
from Example s
order  by s.order_number, s.contract_number;
spool off;
2 голосов
/ 20 апреля 2011

Это должно обеспечить разумное форматирование. Вы, конечно, можете свободно указать свои собственные настройки для максимальной ширины столбцов char и что делать со столбцами LONG, RAW и LOB.

SELECT 'COLUMN ' || column_name || ' FORMAT ' ||
       CASE
          WHEN data_type = 'DATE' THEN
           'A9'
          WHEN data_type LIKE '%CHAR%' THEN
           'A' ||
           TRIM(TO_CHAR(LEAST(GREATEST(LENGTH(column_name),
                        data_length), 40))) ||
           CASE
              WHEN data_length > 40 THEN
               ' TRUNC'
              ELSE
               NULL
           END
          WHEN data_type = 'NUMBER' THEN
           LPAD('0', GREATEST(LENGTH(column_name),
           NVL(data_precision, data_length)), '9') ||
           DECODE(data_scale, 0, NULL, NULL, NULL, '.' ||
           LPAD('0', data_scale, '0'))
          WHEN data_type IN ('RAW', 'LONG') THEN
           'A1 NOPRINT'
          WHEN data_type LIKE '%LOB' THEN
           'A1 NOPRINT'
          ELSE
           'A' || TRIM(TO_CHAR(GREATEST(LENGTH(column_name), data_length)))
       END AS format_cols
  FROM dba_tab_columns
 WHERE owner = 'SYS'
   AND table_name = 'DBA_TAB_COLUMNS';
1 голос
/ 20 апреля 2011

Немного хак, если вам не нужно или не нужно форматирование XML, но вы можете использовать пакет DBMS_XMLGEN . Этот сценарий должен предоставить вам файл XML для произвольного запроса с полным именем столбца в качестве имени тега.

VARIABLE resultXML clob;
SET LONG 100000; -- Set to the maximum size of the XML you want to display (in bytes) 
SET PAGESIZE 0;

DECLARE
   qryCtx DBMS_XMLGEN.ctxHandle;
BEGIN
  qryCtx := dbms_xmlgen.newContext('SELECT * from scott.emp');

  -- now get the result
  :resultXML := DBMS_XMLGEN.getXML(qryCtx);

  --close context
  DBMS_XMLGEN.closeContext(qryCtx);
END;
/

print resultXML
1 голос
/ 09 декабря 2008

Я не думаю, что sqlplus предлагает функциональность, которую вы запрашиваете. Возможно, вы сможете автоматизировать форматирование, используя некоторый язык сценариев, такой как Perl или Python. Другими словами, запросите представление ALL_TAB_COLS для схемы и таблицы, а затем динамически создайте сценарий с атрибутом столбца формата. Конечно, это будет работать, только если у вас есть разрешение на запрос представления ALL_TAB_COLS (или другого аналога).

Это быстрое подтверждение концепции, которое я бросил вместе:

#!/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 )
0 голосов
/ 18 мая 2011

У меня была такая же проблема при попытке реализовать эту функцию в VoraX . В следующей версии я имею в виду следующее решение:

set feedback off 
set serveroutput on
declare
  l_c number;
  l_col_cnt number;
  l_rec_tab DBMS_SQL.DESC_TAB2;
  l_col_metadata DBMS_SQL.DESC_REC2;
  l_col_num number;
begin
  l_c := dbms_sql.open_cursor;
  dbms_sql.parse(l_c, '<YOUR QUERY HERE>', DBMS_SQL.NATIVE);
  DBMS_SQL.DESCRIBE_COLUMNS2(l_c, l_col_cnt, l_rec_tab);
  for colidx in l_rec_tab.first .. l_rec_tab.last loop
    l_col_metadata := l_rec_tab(colidx);
    dbms_output.put_line('column ' || l_col_metadata.col_name || ' heading ' || l_col_metadata.col_name);
  end loop;
  DBMS_SQL.CLOSE_CURSOR(l_c);
end;

Вместо настройки размеров столбцов, форматирования и прочего просто задайте заголовок столбца с нужным именем столбца. Я думаю, что тот же подход будет работать и с решением DBA_TAB_COLUMNS, но я предпочитаю DBMS_SQL, так как он также учитывает псевдонимы и получает только те столбцы, которые вы запрашиваете.

РЕДАКТИРОВАТЬ: Использование только «заголовок столбца» не работает. Все еще необходимо использовать операторы "формата столбца". Поэтому, пожалуйста, проигнорируйте мой предыдущий ответ.

...