Many years ago Tom Kyte published a small PL/SQL procedure to output each row in a table as a list of (column_name , value). I often use the original version, even though Tom refined it several times over the years. From time to time the links in my blog that I’ve set up to point to Tom’s code have simply stopped working so I’ve decided to publish a reference copy on my blog in case newer readers need to find a copy and the current link above stops working.
rem rem Script: print_table.sql rem Dated: Nov 2001 rem Author: Tom Kyte - from Expert One on One Oracle. rem rem Purpose: rem Prints the results of a query one column per line. rem rem Created as a 'authid current_user' so that it can rem access any table that the caller is allowed to access rem from the SQL*Plus prompt. rem rem A suitably privilefed user could also make this publicly rem available through the public synonym and grant at the end rem of the script rem rem Minor modifications by Jonathan Lewis to separate rows rem in the result set, and report the number of rows returned rem create or replace procedure print_table( p_query in varchar2 ) authid current_user is l_theCursor integer default dbms_sql.open_cursor; l_columnValue varchar2(4000); l_status integer; l_descTbl dbms_sql.desc_tab; l_colCnt number; l_rowcnt number := 0; begin execute immediate 'alter session set nls_date_format=''dd-mon-yyyy hh24:mi:ss'' '; dbms_sql.parse( l_theCursor, p_query, dbms_sql.native ); dbms_sql.describe_columns( l_theCursor, l_colCnt, l_descTbl ); for i in 1 .. l_colCnt loop dbms_sql.define_column(l_theCursor, i, l_columnValue, 4000 ); end loop; l_status := dbms_sql.execute(l_theCursor); while ( dbms_sql.fetch_rows(l_theCursor) > 0 ) loop for i in 1 .. l_colCnt loop dbms_sql.column_value( l_theCursor, i, l_columnValue ); dbms_output.put_line( rpad( l_descTbl(i).col_name, 30 ) || ' : ' || l_columnValue ); end loop; dbms_output.new_line; dbms_output.put_line( '-----------------' ); dbms_output.new_line; l_rowcnt := l_rowcnt + 1; end loop; dbms_output.put_line(l_rowcnt || ' rows selected'); execute immediate 'alter session set nls_date_format=''dd-mon-rr'' '; exception when others then execute immediate 'alter session set nls_date_format=''dd-mon-rr'' '; raise; end; / -- create public synonym print_table for print_table; -- grant execute on print_table to public;
The reason I’m publishing this now is that I’m about to publish the third variant of a piece of code I wrote many years ago, and first blogged about in 2012.
+ Another simple one-query variant: http://orasql.org/2013/04/02/sqlplus-tips-2/
Scripts:
https://github.com/xtender/xt_scripts/blob/master/print_table.sql
https://github.com/xtender/xt_scripts/blob/master/print_last.sql
based on xmltable():
Comment by Sayan Malakshinov — November 26, 2020 @ 10:09 am GMT Nov 26,2020 |
Hi Jonathan & Sayan,
Regarding the passing of the query as a parameter by using table(xmlsequence(cursor(&1))) ( like in script print_last.sql variant 2 )
vs using dbms_xmlgen.getxmltype(q'[ &query ]’) , there are some interesting remarks in Stew Ashton’s post here:
https://stewashton.wordpress.com/2018/05/18/print-a-table-with-one-column-name-value-per-row/
and the comments in that post.
For some reason, using CURSOR(&query) instead of a call to DBMS_XMLGEN does miss the columns having NULL values
from the query XML result, not clear to me why.
Best Regards,
Iudith Mentzel
Comment by iudith — November 27, 2020 @ 11:45 am GMT Nov 27,2020 |
Iudith,
Thanks for the comment and the link to Stew’s blog note.
As you say, interesting comments
Regards
Jonathan Lewis
Comment by Jonathan Lewis — November 27, 2020 @ 11:53 am GMT Nov 27,2020 |
Hi Iudith,
Yes, I remember that from the Steven’s post we both discussed in 2011: http://plsql-challenge.blogspot.com/2011/02/different-kind-of-challenge-for-your.html
:)
Usually I don’t need to NULLs in such output, because it consumes extra space, so we see less info on the screen. But it’s easy to enable NULL output: https://github.com/xtender/xt_scripts/blob/master/print_table_nulls.sql
Comment by Sayan Malakshinov — November 27, 2020 @ 12:51 pm GMT Nov 27,2020 |
Sayan,
Thanks for the links and further examples of generating this type of output.
Regards
Jonathan Lewis
Comment by Jonathan Lewis — November 27, 2020 @ 11:54 am GMT Nov 27,2020 |
One more version of the print_table that I’ve been using for some time, authored by Valentin Nikotin:
Comment by Timur Akhmadeev — November 26, 2020 @ 11:05 am GMT Nov 26,2020 |
Timur,
Thanks for the further example of coding for this type of output.
Regards
Jonathan Lewis
Comment by Jonathan Lewis — November 27, 2020 @ 11:55 am GMT Nov 27,2020 |
[…] a little cosmetic work on it), and then passes the resulting string to a verion of Tom Kyte’s print_table() routine which produces the following […]
Pingback by Row sizes 3 | Oracle Scratchpad — November 26, 2020 @ 12:08 pm GMT Nov 26,2020 |
Hi,
“each row in a table as a list of (column_name , value)”
It can be very useful. A problem with compatibility is not to check a native feature exists and to lose time. In this case I notice I don’t really have to adapt print_table.
Regards,
Phil Florent
Comment by Phil Florent — November 27, 2020 @ 4:14 pm GMT Nov 27,2020 |
[…] few weeks ago Jonathan Lewis has published a note about Tom Kyte’s print_table – a small PL/SQL procedure to output each row in a table as a list of (column_name , value). […]
Pingback by Yet another PRINT_TABLE - as a SQL Macro! — December 20, 2020 @ 9:57 pm GMT Dec 20,2020 |
Hi Jonathan,
starting with 19.6 there is another easy way – to use a SQL macro: https://blog.sqlora.com/en/yet-another-print_table-as-a-sql-macro/
Best regards,
Andrej Pashchenko
Comment by Andrej Pashchenko — December 20, 2020 @ 10:05 pm GMT Dec 20,2020 |
[…] a few column formats to make the output readable (though sometimes I can take advantage of the “print_table()” procedure that Tom Kyte published a long time ago. It only takes a little time to get the code […]
Pingback by Lock Types | Oracle Scratchpad — February 18, 2021 @ 10:21 am GMT Feb 18,2021 |
[…] the usual problem of used extents at the top end of a file can apply even for SYSAUX, and it’s highly likely that it will be […]
Pingback by SYSAUX Occupants | Oracle Scratchpad — March 7, 2022 @ 11:32 am GMT Mar 7,2022 |