Monday, May 10, 2010

Oracle: Generate a CSV output of your SQL Query


Recently I have been asked to create a function that could generate a comma separated (CSV) output of a given SQL query. Here I am sharing the source code of that function with a hope that it could be useful to someone for sure. In order to achieve this I am using DBMS_SQL packages.
Dynamic SQL lets you create a procedure that operates on a table whose name is not known until runtime. Additionally, DBMS_SQL enables you to parse any data manipulation language (DML) or data definition language (DDL) statement. Therefore, you can parse DDL statements directly using PL/SQL.

NOTE: Before you start using DBMS_SQL, you need to make sure that it is installed and that the appropriate users have access to this package.

For more information on DBMS_SQL package: http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96612/d_sql.htm

FUNCTION generate_csv( par_query CLOB ,
                       par_include_header NUMBER DEFAULT 1

                     ) RETURN CLOB

IS

l_cursor PLS_INTEGER;
_rows PLS_INTEGER;
l_col_cnt PLS_INTEGER;

l_desc_tab DBMS_SQL.desc_tab;

l_buffer CLOB;

l_row_data CLOB ;


BEGIN

l_cursor := DBMS_SQL.open_cursor;

DBMS_SQL.parse(l_cursor, par_query , DBMS_SQL.native);

DBMS_SQL.describe_columns (l_cursor, l_col_cnt, l_desc_tab);


FOR i IN 1 .. l_col_cnt LOOP

    DBMS_SQL
.define_column(l_cursor, i, l_buffer);

END LOOP;


l_rows := DBMS_SQL.execute(l_cursor);
-- Adding column header.

IF par_include_header = 1 THEN   FOR i IN 1 .. l_col_cnt LOOP
   l_buffer := l_desc_tab(i).col_name ;
   l_row_data := l_row_data || l_buffer ;

   IF i <> l_col_cnt THEN 
      row_data := l_row_data || ',';
   END IF ;

  END LOOP;
l_row_data := l_row_data || CHR(13) ; --Add carriage return
END IF;


-- Appending data.LOOPEXIT WHEN DBMS_SQL.fetch_rows(l_cursor) = 0;
FOR i IN 1 .. l_col_cnt LOOP --Loop through all columns
  DBMS_SQL.COLUMN_VALUE(l_cursor, i, l_buffer);
  l_row_data := l_row_data || l_buffer ;
  IF i <> l_col_cnt THEN
    l_row_data := l_row_data || ',';
  END IF ;
END LOOP;


l_row_data := l_row_data || CHR(13) ; --Add carriage return

END LOOP;
RETURN l_row_data;

EXCEPTION
WHEN OTHERS THEN

IF DBMS_SQL.is_open(l_cursor) THEN
  DBMS_SQL
.close_cursor(l_cursor);

END IF;


RETURN 'Error :' || SQLERRM || CHR(13) || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE ;

END generate_csv ;

Example:
SELECT generate_csv('SELECT object_id,object_name,object_type FROM user_objects WHERE ROWNUM <=20') data FROM DUAL;

Result :

OBJECT_ID,OBJECT_NAME,OBJECT_TYPE
74516,AA_CU_VW,VIEW
74517,AA_LC_VW,VIEW
89245,AA_PO,VIEW
89246,AA_PO1,VIEW
74336,ACTIVITY_ROLLFORWARD_SUMMARY,VIEW
73833,APPSCREENS,TABLE
73834,APPSCREENSSCREENNAME,INDEX
73835,APPUSERS,TABLE
73836,APPUSERSUSERNAME,INDEX
197790,BANK,TABLE
197791,BANKBANKNUM,INDEX
202243,BENEY,TABLE
202244,BENEYBENEYACCT,INDEX
195188,BIN$f9BuwtUHsjDgQ6wQEUKyMA==$0,INDEX
195189,BIN$f9BuwtUIsjDgQ6wQEUKyMA==$0,INDEX
195190,BIN$f9BuwtUJsjDgQ6wQEUKyMA==$0,INDEX
195191,BIN$f9BuwtUKsjDgQ6wQEUKyMA==$0,INDEX
195192,BIN$f9BuwtULsjDgQ6wQEUKyMA==$0,INDEX
195193,BIN$f9BuwtUMsjDgQ6wQEUKyMA==$0,INDEX
195194,BIN$f9BuwtUNsjDgQ6wQEUKyMA==$0,INDEX





No comments:

Post a Comment