2008-12-09 40 views
6

Theo mặc định sqlplus cắt bớt tên cột theo chiều dài của kiểu dữ liệu cơ bản. Nhiều tên cột trong cơ sở dữ liệu của chúng tôi được đặt trước bằng tên bảng và do đó trông giống hệt nhau khi cắt ngắn.Ngăn chặn cắt xén các tên cột, không có định dạng cột riêng lẻ

Tôi cần chỉ định các truy vấn * đã chọn cho các DBA từ xa trong môi trường sản xuất bị khóa và kéo các kết quả đã được tạo ra để chẩn đoán. Có quá nhiều cột để chỉ định định dạng cột riêng lẻ. Có sqlplus cung cấp bất kỳ tùy chọn để thống nhất đánh bại tên cột cắt ngắn?

(Tôi đang sử dụng SET đánh dấu HTML trên, mặc dù tôi có thể sử dụng một số phương thức khác, csv, vv miễn là nó mang lại sản lượng không viết tắt lại.)

Trả lời

1

Tôi không nghĩ sqlplus cung cấp các chức năng bạn đang yêu cầu . Bạn có thể tự động định dạng, sử dụng một số loại ngôn ngữ kịch bản như Perl hoặc Python. Nói cách khác, truy vấn chế độ xem ALL_TAB_COLS cho giản đồ và bảng, sau đó tạo tập lệnh động với thuộc tính cột định dạng. Điều này sẽ chỉ hoạt động, tất nhiên, nếu bạn có quyền truy vấn chế độ xem ALL_TAB_COLS (hoặc một số tương đương khác).

Đây là một khái niệm bằng chứng-of-nhanh chóng tôi đã ném với nhau:

#!/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

Cảm ơn mã python, rất tiếc khách hàng của chúng tôi nghiêm cấm cài đặt bất kỳ phần mềm nào khác trong môi trường sản xuất của họ. Thậm chí không grep hoặc đuôi. Ugh. Vì vậy, đó là sqlplus hoặc bust. –

+0

Tìm thấy điều này là hữu ích vì lý do hoàn toàn không liên quan. Rất vui khi bạn đăng nó! :-D –

3

Một điều bạn có thể thử là để tự động tạo ra "cột x dạng A20" lệnh. Một cái gì đó như sau:

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 

Lưu ý rằng mẫu này sẽ chỉ hoạt động với VARCHAR2. Bạn sẽ cần phải thêm giải mã ví dụ để thay đổi lệnh "cột" được tạo cho DATE hoặc NUMBER.

CẬP NHẬT: Hóa ra SQL ban đầu không thực sự thay đổi hành vi của SQL * Plus. Điều duy nhất tôi có thể nghĩ là để đổi tên các tên trường để một nhân vật giá trị A, B, C, vv .. theo cách sau:

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

Nó sẽ tạo đầu ra tương tự như:

column DEPT_NO heading "A" 
column NAME heading "B" 
column SUPERVIS_ID heading "C" 
column ADD_DATE heading "D" 
column REPORT_TYPE heading "E" 
+0

Hmm, một chút nặng tay, nhưng tôi đoán rằng có thể làm việc. Ngoại trừ tôi không nghĩ rằng bạn có nghĩa là data_length. Nó sẽ không chỉ là độ dài của kiểu dữ liệu cơ bản, và do đó dẫn đến hành vi sqlplus mặc định? Có thể có một hoạt động chuỗi dài có thể được áp dụng cho tên cột không? –

+0

Chris, bạn đã đúng. Tôi chỉ nhận ra rằng nó chỉ ảnh hưởng đến định dạng của các giá trị chứ không phải định dạng của tiêu đề. Chọn câu lệnh cho một cách tiếp cận khác một chút là trong bản cập nhật của bài đăng. –

+0

Vì vậy, tôi sẽ kết thúc hiển thị cho tôi cột có nhãn A, B, C, vv ... Nhưng mục tiêu của tôi là cho đầu ra để hiển thị tên cột ban đầu, không được cắt ngắn, để tôi có thể cho biết cột nào là. –

2

Điều này sẽ cung cấp một số định dạng hợp lý. Tất nhiên, bạn có thể tự do thay thế các tùy chọn của riêng mình cho chiều rộng tối đa của các cột char và phải làm gì với các cột LONG, RAW và 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

Đó là một chút hack nếu bạn không cần hoặc muốn định dạng XML, nhưng bạn sẽ có thể sử dụng DBMS_XMLGEN package. Tập lệnh này sẽ cung cấp cho bạn một tệp XML cho truy vấn tùy ý có tên cột đầy đủ làm tên thẻ.

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 
0

Tôi đã gặp sự cố tương tự khi cố triển khai tính năng này trong VoraX. Trong phiên bản tiếp theo, tôi nhớ rằng giải pháp sau đây:

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; 

Thay vì điều chỉnh kích thước cột, định dạng và nội dung chỉ thực thi tiêu đề cột với tên cột bạn muốn. Tôi nghĩ rằng cách tiếp cận tương tự cũng sẽ làm việc với giải pháp DBA_TAB_COLUMNS nhưng tôi thích DBMS_SQL vì nó cũng xem xét các bí danh và nó chỉ được các cột bạn truy vấn.

CHỈNH SỬA: Chỉ sử dụng "tiêu đề cột" không hoạt động. Vẫn cần sử dụng các câu lệnh "định dạng cột". Vì vậy, xin vui lòng bỏ qua câu trả lời trước đây của tôi.

2

Không có giải pháp nào được đề xuất để hiển thị tên cột gốc, vì vậy tôi không chắc tại sao mọi người bỏ phiếu cho họ ... Tôi có "hack" hoạt động cho yêu cầu ban đầu, nhưng tôi thực sự không Không thích nó ... Đó là bạn thực sự gắn thêm hoặc tiền tố một chuỗi vào truy vấn cho mỗi cột để chúng luôn đủ dài cho tiêu đề cột. Nếu bạn đang ở trong một chế độ HTML, như là poster, có rất ít tác hại bởi một chút khoảng trắng thêm ... Nó sẽ tất nhiên làm chậm truy vấn của bạn ...

ví dụ:

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; 

Tất nhiên bạn có thể viết thủ tục lưu trữ để làm điều gì đó tốt hơn, nhưng thực sự có vẻ như quá mức cho trường hợp đơn giản này.

Điều này vẫn không đáp ứng được yêu cầu áp phích gốc. Trong đó, nó yêu cầu liệt kê thủ công trên các cột và không sử dụng select *. Nhưng ít nhất nó là giải pháp hoạt động khi bạn sẵn sàng để chi tiết ra các lĩnh vực.

Tuy nhiên, vì thực sự không có vấn đề gì khi có quá nhiều trường trong HTML, có một cách khá đơn giản để sửa giải pháp của Chris để làm việc với ví dụ này. Đó là chỉ cần chọn một sử dụng oracle giá trị tối đa sẽ cho phép. Đáng buồn thay điều này vẫn sẽ không thực sự làm việc cho mọi lĩnh vực của mỗi bảng, trừ khi bạn rõ ràng thêm định dạng cho mọi loại dữ liệu. Giải pháp này cũng sẽ không hoạt động cho các phép nối, vì các bảng khác nhau có thể sử dụng cùng một tên cột nhưng một kiểu dữ liệu khác nhau.

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; 
Các vấn đề liên quan