Where is the rest of Oracle's V$ view definitions? - oracle

The view V$FIXED_VIEW_DEFINITION contains the definition of all V$ views. However, the datatype is VARCHAR2(4000), so only the first 4000 characters of the view's body are displayed:
SELECT column_name, data_type, data_length
FROM dba_tab_cols
WHERE table_name = 'V_$FIXED_VIEW_DEFINITION';
COLUMN_NAME DATA_TYPE DATA_LENGTH
--------------- --------- -----------
VIEW_NAME VARCHAR2 128
VIEW_DEFINITION VARCHAR2 4000
CON_ID NUMBER 22
This works fine for views which are shorter, but for others, like V$SESSION, the query text stops right after character 4000:
SELECT * FROM v$fixed_view_definition WHERE view_name = 'GV$SESSION';
VIEW_NAME VIEW_DEFINITION
---------- --------------------------------------------
GV$SESSION select s.inst_id, ... ,decode(bitand(s.ksuse
here it stops abruptly ^
Now, obviously, Oracle has stored the full text somewhere, and the function DBMS_UTILITY. EXPAND_SQL_TEXT T reconstructs the full query, but not without doing strange things to the query like quoting all columns, introducing alias etc:
DECLARE
c CLOB;
i NUMBER := 1;
linelen CONSTANT NUMBER := 100;
BEGIN
DBMS_UTILITY.EXPAND_SQL_TEXT('SELECT * FROM V$SESSION', c);
LOOP
EXIT WHEN i > DBMS_LOB.GETLENGTH(c);
DBMS_OUTPUT.PUT_LINE(DBMS_LOB.SUBSTR(c, linelen, i));
i := i + linelen;
END LOOP;
END;
/
SELECT "A1"."SADDR" "SADDR","A1"."SID" "SID","A1"."SERIAL#" "SERIAL#","A1"."AUDS
ID" "AUDSID","A1"."PADDR" "PADDR","A1"."USER#" "USER#","A1"."USERNAME" "USERNAME
...
So, where is the rest of the V$ query bodies?

For the sake of having a clean answer, it sounds like you discovered the full fixed view source queries compiled into the Oracle binary by using
strings $ORACLE_HOME/bin/oracle
and grepping the output for a specific view.
Burleson had provided a hint that the fixed view synonyms are created by the $ORACLE_HOME/rdbms/admin/ catalog scripts (specifically cdfixed.sql).

try this,
spool C:\Users\test\Downloads\VW_DDL.txt
SET LONG 200000 LONGCHUNKSIZE 500000 PAGESIZE 0 LINESIZE 1000 FEEDBACK OFF VERIFY OFF TRIMSPOOL ON
SELECT DBMS_METADATA.get_ddl ('VIEW', view_name, 'SYSADM')
FROM all_views
WHERE owner = 'SYSADM'
AND view_name IN (' ');
SET PAGESIZE 14 LINESIZE 100 FEEDBACK ON VERIFY ON
spool off

Related

Is there any PL/SQL script to modify column value of each table in each schema of Oracle Database

I have written pl/sql code to modify column values in a table of one schema. But I need to execute the same script in each table of each schema. I will take the list of the table name, column name from spreadsheet.
define schema_name = 'D';
define hours_offset = '(-3/24)';
set echo off;
set timi off;
set heading off;
set feedback off;
set linesize 250;
spool convert_01.sql
select 'set echo on;' from dual;
select 'set timi on;' from dual;
select 'set heading on;' from dual;
select 'set feedback on;' from dual;
select 'set linesize 250;' from dual;
select 'spool convert_01.log;' from dual;
select 'update '||owner||'.'||table_name||' set '||column_name||'
='||column_name||' + &hours_offset;'
from dba_tab_columns where owner = '&schema_name' and
(
data_type = 'DATE' or
data_type like 'TIMESTAMP%'
) and
data_type not like 'TIMESTAMP%WITH TIME ZONE'
order by owner, table_name, column_name;
select 'spool off;' from dual;
spool off;
I need to execute the same script in each table of each schema
That's most probably not true. There are users (schemas) you shouldn't modify at all, e.g. SYS, SYSTEM, CTXSYS, APEX180200 and such.
Therefore, you'd rather collect list of users you want to skip (or the ones you want to affect; it's up to you). That list would then be used instead of '&schema_name'.
A simple option is to store list of users into a table and use its contents as a subquery in your current script.
Unrelated, but:
I have written pl/sql code ...
Nope; what you wrote is a pure SQL script readable by SQL*Plus (and, possibly, some other tools which understand commands you used).

Spooling Serveroutput into a CSV file

I got the task to update a rather big file that consists of many update and delete statements.
First things first would be to check, which statements are actually needed / used.
I would like to spool this into a separate file, but it is difficult to get it into a nice format.
For example:
set serveroutput on
spool xxx.csv
update xx set yy where a = b;
Creates a file like:
sql: update xx.....
1100 rows updated.
The closest i got to my desired output is to use something like:
spool xxx.csv
select 'update xx set yy where a = b;' query, count(x) count from xx where (update where clause)
This would work mostly well (except for multiline queries), but it would require me to rewrite all update / delete statements and there are a lot.
Does anyone have an idea how I could solve this the best way?
The best outcome would be a file like:
Query Count
update xx ... 1100
Thanks in advance!
You can use SQL%ROWCOUNT and the below select to achieve your requirement
DECLARE
l_sql_text VARCHAR2(32767);
l_sql_count NUMBER;
BEGIN
insert into tttt values(4);
l_sql_count:= SQL%rowcount;
SELECT
(
SELECT t2.sql_fulltext
FROM v$sql t2
WHERE t1.prev_sql_id = t2.sql_id
AND t1.prev_child_number = t2.child_number ) prev_sql_fulltext
INTO l_sql_text
FROM v$session t1
WHERE t1.audsid = Sys_context('userenv', 'sessionid');
dbms_output.put_line('Query,Count');
dbms_output.Put_line(l_sql_text
||','
||l_sql_count);
END;
Output
Query,Count
INSERT INTO TTTT VALUES(4),1

Execute SQL query in another Query as result

I have a table which contains SQL query as one of the columns. Based on record id, I want to execute SQL query which is in the record.
Master_Table
------------------------------
|Rec_ID | Query |
------------------------------
|1 | SELECT * from EMP |
------------------------------
|2 | SELECT * FROM DEPT |
------------------------------
SELECT Query FROM Master_Table WHERE Rec_ID=1
I am expecting that If I select Rec_Id =1, I have to EMP records.
If I select Rec_Id=2, I need to get Dept records.
Is it possible to do it in SQL query?
There are a few ways to run dynamic SQL in SQL. In 18c we can use a polymorphic table function. If it's OK to get the results as XML we can use DBMS_XMLGEN.getXML. If we're able to create custom PL/SQL objects we can use Oracle data cartridge to build a Method4 solution.
For example, after installing Method4, we can run SQL like this:
select * from table(method4.dynamic_query(
'
select query
from master_table
where rec_id = 1
'
));
The above code will work with the below sample schema:
create table master_table as
select 1 rec_id, 'SELECT * from EMP' query from dual union all
select 2 rec_id, 'SELECT * FROM DEPT' query from dual;
create table emp(emp_name varchar2(100));
create table dept(dept_name varchar2(100));
The preceding information literally answers your question. But I agree with Mark D Powell that this design is often a bad idea and we should only create code like this after we've evaluated alternative designs.
Vsau, I agree with JNevill in that you need PL/SQL to execute the 'SQL' from your table column. Also I will add that these kind of designs are usually a bad idea. You want your application SQL to be static sql using bind variables otherwise your system will suffer from too high a percentage of hard parses and resulting contention on the dictionary objects and you may run into shared pool fragmentation issues.
You can use sys_refcursor
SQL> create or replace function get_emp_tab return sys_refcursor is
v_rc sys_refcursor;
v_sql varchar2(4000);
begin
select query into v_sql from Master_Table where Rec_ID = 1
open v_rc for v_sql;
return v_rc;
end;
/
SQL> declare
v_rc sys_refcursor;
begin
:v_rc := get_emp_tab;
end;
/
SQL> print v_rc;

how to output any given table in oracle to csv using sqlplus

I want a way of dynamically exporting any given table in oracle 11g to a csv using sql*plus - instead of needing to explicitly hard code the column names each time.
Please use following syntax.
SET MARKUP HTML ON SPOOL ON
HEAD "<title>Data Extract</title> - <meta http-equiv='Content-Type' content='application/vnd.ms-excel;'>
<style type='text/css'>
</style>"
SET ECHO OFF
SPOOL output.xls
select * from &tablename ;
spool off
exit
Enter tablename when prompted.
Abhi
You can use the SET Colsep option.
SET COLSEP ","
SET PAGES 0
SET FEEDBACK OFF
SPOOL output.csv
select * from HR.employees;
spool off
exit
After searching stack overflow I could not find an exact answer to this problem - therefore I developed my own solution.
Here is the sql script that I wrote:
SET echo off
SET verify off
SET heading off
SET pages 50000
SET feedback off
SET newpage none
SET termout off
SET linesize 900
SET trimspool on
SET serveroutput on
define table_name = &1
define spool_path = &2
var rc refcursor
column qry new_val capture
SELECT 'select ''"'' || ' || listagg(column_name,' || ''","'' || ') within group (order by column_id) || ' || ''"'' as rec from &table_name' qry
FROM user_tab_cols
WHERE table_name = '&table_name';
spool &spool_path
SELECT listagg(column_name,',') WITHIN GROUP (ORDER BY column_id)
FROM user_tab_cols
WHERE table_name = '&table_name';
BEGIN
FOR v_rec IN (&capture) LOOP
dbms_output.put_line(v_rec.rec);
END LOOP;
END;
/
spool off
EXIT
The script requires two parameters - the first parameter is the table name, and the second is the spool path.
Essentially the first query:
SELECT 'select ''"'' || ' || listagg(column_name,' || ''","'' || ') within group (order by column_id) || ' || ''"'' as rec from &table_name' qry
FROM user_tab_cols
WHERE table_name = '&table_name';
Dynamically creates a new select statement (which loads into the &capture substitution variable) using user_tab_cols and listagg to force each column name onto a single line - this dynamically created select statement will essentially concatenate each column together separated by commas. Later when we spool we loop through the dynamically generated select statement to produce each row of data.
The header is produced by a similar query (the first action once we begin spooling), however for this we can just listagg the column header names together directly.
It is easier to understand by testing the two queries on a table of your choice to see the result!

Prevent output of SPOOL from being wrapped

I'm trying to generate all DDLs for objects in a Database using the SPOOL command in SQLPLUS:
SET trimspool ON
SET wrap off
SET heading off
SET linesize 300
SET echo off
SET pages 999
SET long 90000
Col object_type format a10000
Col object_name format a10000
Col owner format a10000
spool export.out
SELECT DBMS_METADATA.GET_DDL(object_type, object_name, owner)
FROM all_OBJECTS
WHERE OWNER = 'DMALM'
and object_type not like '%PARTITION'
and object_type not like '%BODY'
and object_type not like '%LOB';
spool off
quit
But the output file I get is cut at col #80.
How can I prevent the output file from being wrapped?
You need to also do:
SET longchunksize 90000
As the documentation says:
The default width of datatype columns is the width of the column in the database. The column width of a LONG, BLOB, BFILE, CLOB, NCLOB or XMLType defaults to the value of SET LONGCHUNKSIZE or SET LONG, whichever is the smaller.
You're setting LONG already, but LONGCHUNKSIZE is still at its default value of 80, so you need to increase that to match. You can see all your current settings with show all.
This preserves the line breaks and indentation applied by default.
How about using word_wrapped?
SET trimspool ON
SET heading off
SET linesize 300
SET echo off
SET pages 999
SET long 90000
set termout off
column txt format a121 word_wrapped
Col object_type format a10000
Col object_name format a10000
Col owner format a10000
spool export.out
SELECT DBMS_METADATA.GET_DDL(object_type, object_name, owner)txt
FROM all_OBJECTS
WHERE OWNER = 'DMALM'
and object_type not like '%PARTITION'
and object_type not like '%BODY'
and object_type not like '%LOB';
spool off
quit
Sounds like you may want to try:
set longchunksize 100
or equivalent. Experiment with the number see if it helps.
Source Oracle Docs
The following works. You can download all SPs under one schema. You can also download one SP at a time.
CREATE or replace DIRECTORY DIR_DDL AS '/dir_name';
grant read, write on directory DIR_DDL to user_name;
-- ====================================================
-- NOTE: Need to use the object owner user, not SYS.
-- ====================================================
DECLARE
v_ddl_clob CLOB;
BEGIN
FOR c IN ( SELECT object_name, object_type
FROM dba_objects
WHERE object_type IN ('PROCEDURE')
AND OWNER = 'SYS'
AND object_name = 'SP_NAME' )
LOOP
-- You want "/" in a new line. Otherwise, it will not work
v_ddl_clob := dbms_metadata.get_ddl(c.object_type, c.object_name) ||'
/';
-- write to SQL directory :
dbms_xslprocessor.clob2file(v_ddl_clob, 'DIR_DDL', c.object_name||'.sql');
END LOOP;
END;
/

Resources