How get copy of objects from oracle database - oracle

I have plan to do a release for our product. we are using Oracle forms to develop our software.
So I have two type of object for release
Front-end => Oracle forms
Back-end => Oracle Database Program (Procedure, function and Package)
One of the important part of release is we need to have a back up so if any thing happen we can use the older version.
By the way, for front end object I will use some batch file to create a back up for my front end objects but for Back-end object I dont know how I can get a copy of function, procedure or package(spec & body) automatically.
Any idea how I can do it automatically? please advice me.
we are using oracle 10g & 9i

"In my company sometimes developer apply some package or function
during the webbex so sometimes customer production is not same as our
pvcs."
So what is the point of storing code in a repository? What is the point of testing a configuration? What is the point of release management?
If these cowboy developers who muck around with your customers' production environments are your staff you need to discipline them. Enforce process to guarantee that only certified configurations are deployed. If emergency tweaks are required these should be retrofitted into the official build.
If these developers actually work for the customer, then I suppose you cannot stop them. But you don't have to support them, and you don't have to be responsible for their changes. (unless the sales contract says you have to, which wouldn't surprise me.)

(Apologies for the code-blob).
Here's some code I've used to handle issues like this:
PROCEDURE DUMP_CLOB(aCLOB IN CLOB,
hOutput_file IN UTL_FILE.FILE_TYPE) IS
nCLOB_length NUMBER;
nCLOB_offset NUMBER := 1;
nMax_chunk_size NUMBER := 32767;
strChunk VARCHAR2(32767);
BEGIN
nCLOB_length := DBMS_LOB.GETLENGTH(aCLOB);
WHILE nCLOB_offset <= nCLOB_length LOOP
strChunk := DBMS_LOB.SUBSTR(aCLOB, nMax_chunk_size, nCLOB_offset);
UTL_FILE.PUT(hOutput_file, strChunk);
nCLOB_offset := nCLOB_offset + LENGTH(strChunk);
END LOOP;
UTL_FILE.PUT_LINE(hOutput_file, ';');
END DUMP_CLOB;
PROCEDURE DUMP_PRIVS(strOwner IN VARCHAR2,
strObject_name IN VARCHAR2,
hOutput_file IN UTL_FILE.FILE_TYPE) IS
BEGIN
FOR pRow IN (SELECT *
FROM DBA_TAB_PRIVS p
WHERE p.OWNER = strOwner AND
p.TABLE_NAME = strObject_name)
LOOP
UTL_FILE.PUT_LINE(hOutput_file, 'GRANT ' || pRow.PRIVILEGE || ' ON ' ||
strOwner || '.' || strObject_name ||
' TO ' || pRow.GRANTEE || ';');
END LOOP;
END DUMP_PRIVS;
PROCEDURE DUMP_OBJECT(strOwner IN VARCHAR2,
strObject_name IN VARCHAR2,
hOutput_file IN UTL_FILE.FILE_TYPE)
IS
clobDDL CLOB;
strCurr_object_name VARCHAR2(100);
BEGIN
FOR rowObject IN (SELECT *
FROM SYS.DBA_OBJECTS o
WHERE o.OWNER = strOwner AND
o.OBJECT_NAME = strObject_name AND
o.OBJECT_TYPE <> 'TABLE PARTITION')
LOOP
strCurr_object_name := NVL(rowObject.SUBOBJECT_NAME, rowObject.OBJECT_NAME);
UTL_FILE.PUT_LINE(hOutput_file, '-- DDL for ' || LOWER(rowObject.OBJECT_TYPE) || ' ' ||
strOwner || '.' || strCurr_object_name);
SELECT DBMS_METADATA.GET_DDL(rowObject.OBJECT_TYPE, strCurr_object_name, strOwner) AS DDL
INTO clobDDL
FROM DUAL;
DUMP_CLOB(clobDDL, hOutput_file);
DUMP_PRIVS(strOwner, strCurr_object_name, hOutput_file);
IF rowObject.OBJECT_TYPE = 'TABLE' THEN
-- Indexes
FOR aRow IN (SELECT DBMS_METADATA.GET_DDL('INDEX', i.INDEX_NAME, i.OWNER) AS clobIndex
FROM DBA_INDEXES I
WHERE I.TABLE_OWNER = strOwner AND
I.TABLE_NAME = strCurr_object_name)
LOOP
DUMP_CLOB(aRow.clobIndex, hOutput_file);
END LOOP; -- Indexes
END IF;
IF rowObject.OBJECT_TYPE IN ('TABLE', 'VIEW') THEN
-- Triggers
FOR aRow IN (SELECT DBMS_METADATA.GET_DDL('TRIGGER', t.TRIGGER_NAME, t.OWNER) AS clobTrigger
FROM DBA_TRIGGERS t
WHERE TABLE_OWNER = strOwner AND
TABLE_NAME = strCurr_object_name)
LOOP
DUMP_CLOB(aRow.clobTrigger, hOutput_file);
END LOOP; -- Triggers
END IF;
END LOOP;
END DUMP_OBJECT;
PROCEDURE DUMP_OBJECT(strOwner IN VARCHAR2,
strObject_name IN VARCHAR2,
strDirectory_name IN VARCHAR2,
strFilename IN VARCHAR2,
strOpen_mode IN VARCHAR2 DEFAULT 'w')
IS
hOutput_file UTL_FILE.FILE_TYPE;
BEGIN
hOutput_file := UTL_FILE.FOPEN(location => strDirectory_name,
filename => strFilename,
open_mode => strOpen_mode);
DUMP_OBJECT(strOwner, strObject_name, hOutput_file);
UTL_FILE.FCLOSE(hOutput_file);
EXCEPTION
WHEN OTHERS THEN
UTL_FILE.FCLOSE(hOutput_file);
RAISE;
END DUMP_OBJECT;
I suggest putting these procedures into a package. Call DUMP_OBJECT for the things you want dumped.
Share and enjoy.

Related

Why do I get no output from this query (searching database for string)?

I'm an Oracle/PL/SQL Developer newbie, and I'm struggling to figure out how to see the output of this query:
DECLARE
ncount NUMBER;
vwhere VARCHAR2(1000) := '';
vselect VARCHAR2(1000) := ' select count(1) from ';
vsearchstr VARCHAR2(1000) := '1301 250 Sage Valley Road NW';
vline VARCHAR2(1000) := '';
istatus INTEGER;
BEGIN
DBMS_OUTPUT.ENABLE;
FOR k IN (SELECT a.table_name, a.column_name FROM user_tab_cols a WHERE a.data_type LIKE '%VARCHAR%')
LOOP
vwhere := ' where ' || k.column_name || ' = :vsearchstr ';
EXECUTE IMMEDIATE vselect || k.table_name || vwhere
INTO ncount
USING vsearchstr;
IF (ncount > 0)
THEN
dbms_output.put_line(k.column_name || ' ' || k.table_name);
ELSE
dbms_output.put_line('no output');
END IF;
END LOOP;
dbms_output.get_line(vline, istatus);
END;
I got this script from https://community.oracle.com/tech/developers/discussion/2572717/how-to-search-a-particular-string-in-whole-schema. It's supposed to find a string (vsearchstr) in the entire database. When I run this in PL/SQL Developer 14.0.6, it spits out no errors, says it took 0.172 seconds, but I don't see any output. I'm expecting the output to show under the Output tab:
I know the string '1301 250 Sage Valley Road NW' exists in the database so it should be finding it. Even if it doesn't, the ELSE block should be outputting 'no output'.
From what I understand, dbms_output.put_line() adds the given string to a buffer, and dbms_output.get_line() prints it to the output target (whatever it's set to). I understand that dbms_output needs to be enabled (hence the line DBMS_OUTPUT.ENABLE) and dbms_output.get_line() will only run after the BEGIN/END block it's in completes (I don't know if this means it has to be put outside the BEGIN/END block, but I couldn't avoid certain errors every time I did).
I've read through various stackoverflow posts about this issue, as well as a few external site:
https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68001/dbms_out.htm#1000449
https://www.tutorialspoint.com/plsql/plsql_dbms_output.htm
...but nothing seems to be working.
How can I see the output, or if there's something wrong in the query above, can you tell what it is?
Thanks.
To enable output from DBMS_OUTPUT in PL/SQL Developer see this answer.
I'm looking for an alternative keyword to user_tab_cols for all schemas in the DB
Use ALL_TAB_COLS and catch the exceptions when you do not have enough privileges to read the table (and use quoted identifiers to match the case of user/table/column names):
DECLARE
found_row PLS_INTEGER;
vsearchstr VARCHAR2(1000) := '1301 250 Sage Valley Road NW';
BEGIN
FOR k IN (SELECT owner,
table_name,
column_name
FROM all_tab_cols t
WHERE data_type LIKE '%VARCHAR%'
-- Ignore columns that are too small
AND data_length >= LENGTH(vsearchstr)
-- Ignore all oracle maintained tables
-- Not supported on earlier Oracle versions
AND NOT EXISTS (
SELECT 1
FROM all_users u
WHERE t.owner = u.username
AND u.oracle_maintained = 'Y'
)
)
LOOP
DECLARE
invalid_privileges EXCEPTION;
PRAGMA EXCEPTION_INIT(invalid_privileges, -1031);
BEGIN
EXECUTE IMMEDIATE 'SELECT 1 FROM "' || k.owner || '"."' || k.table_name || '" WHERE "' || k.column_name || '" = :1 AND ROWNUM = 1'
INTO found_row
USING vsearchstr;
dbms_output.put_line('Found: ' || k.table_name || '.' || k.column_name);
EXCEPTION
WHEN invalid_privileges THEN
NULL;
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('Not found: ' || k.table_name || '.' || k.column_name);
END;
END LOOP;
END;
/

To Dynamic SQL or Not

When doing an update, we want to do a concurrency check on the ORA_ROWSCN (Oracle db BTW). So I was thinking of creating a function, where you pass in the ora_rowscn you have, table name, column name and an ID. The function would check would do a select statement based on the table, column and id you've passed in and if the returned ora_rowscn is different from the one you passed in, return a true or false is it's the same.
I do validity check on the table_name and column_name passed in to make sure they exists first.
FUNCTION ConcurrencyCheck (
pi_orarowscn_in IN NUMBER,
pi_table_name IN VARCHAR2,
pi_column_name IN VARCHAR2,
pi_id IN NUMBER
)
RETURN BOOLEAN IS
r_data_out_of_date BOOLEAN := false;
ln_orarowscn_current NUMBER := 0;
lv_sql VARCHAR2(300) := '';
lv_column VARCHAR(20) := '';
lv_table VARCHAR(20) := '';
BEGIN
SELECT table_name INTO lv_table from ALL_TABLES WHERE TABLE_NAME = pi_table_name;
IF lv_table = '' THEN
RAISE NO_DATA_FOUND;
ELSE
SELECT column_name INTO lv_column from USER_TAB_COLUMNS WHERE TABLE_NAME = pi_table_name AND COLUMN_NAME = pi_column_name;
IF lv_column = '' THEN
RAISE NO_DATA_FOUND;
ELSE
lv_sql := 'select ORA_ROWSCN from ' || pi_table_name || ' where ' || pi_column_name || ' = ' || pi_id || '';
EXECUTE IMMEDIATE lv_sql INTO ln_orarowscn_current;
IF ln_orarowscn_current <> pi_orarowscn_in THEN
r_data_out_of_date := true;
END IF;
END IF;
END IF;
RETURN r_data_out_of_date;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE;
WHEN OTHERS THEN
RAISE;
END ConcurrencyCheck;
I do not like the dynamic SQL that I have there. I would much rather (not have dynamic SQL but... ) have it like the following:
lv_sql := 'select ORA_ROWSCN from :table_name where :column_name = :id';
EXECUTE IMMEDIATE lv_sql INTO ln_orarowscn_current USING pi_table_name, pi_column_name, pi_id;
but I keep getting an SQL error saying the table is wrong
The other solution is to create a sub-function for ALL the tables that would return the ORA_ROWSCN for each and a IF ELSE in the main function to call each.
I'm looking for best practice here. Is this a time where dynamic SQL is acceptable? Or should I go the "long" route and create a ton of functions/procedures for each table?
Thank you!
As for the best practices, in these cases it's recommended to use the sys.dbms_assert package.
FUNCTION ConcurrencyCheck(
pi_orarowscn_in IN NUMBER,
pi_table_name IN VARCHAR2,
pi_column_name IN VARCHAR2,
pi_id IN NUMBER
)
RETURN BOOLEAN IS
ln_orarowscn_current NUMBER := 0;
lv_sql VARCHAR2(300) := '';
BEGIN
lv_sql := '
select X.ora_rowscn
from '||sys.dbms_assert.sql_object_name(pi_table_name)||' X
where X.'||sys.dbms_assert.simple_sql_name(pi_column_name)||' = :pi_id
';
execute immediate lv_sql
into ln_orarowscn_current
using in pi_id;
return ln_orarowscn_current <> pi_orarowscn_in;
END ConcurrencyCheck;
Note: If I were in your place, I'd give myself the initial hard time of implementing a metadata-driven code generator for the package of one-check-per-one-table functions that would be, as you may have guessed, static PL/SQL code – giving you all those nice compile-time syntax/semantic checks.

Oracle 10g - Get list of tables from query i'm executing

I am working on internal tools of my organization, I have a automation need currently.
Example input query:
Select name,userid,url,address_line_1 from user join address on
user.user_id = address.user_id where userid = 'xxyy';
what I need is list of tables
user
address
Is there a built in way in Oracle 10G to get the list of tables from this query? Or Is there a python parser that can help me with the list of tables from the query?
Note: This is a basic example, my queries run in several lines and are more complex.
Interesting question.
You could build a little SQL analyzer in PL/SQL using DBMS_FGA. The idea would be:
Automatically modify the input SQL to also use a table with a FGA policy on it
In that FGA policy, you will have access to the current SQL (the first 32K of it, anyway. That's a limitation...)
Use the current SQL to build a throw-away view on the current SQL
Read the throw-away view's dependencies from USER_DEPENDENCIES
Drop the throw-away view.
Here is an example of how it would work:
(I apologize for putting my first name in all the objects; I share this database with others.)
-- Tester
BEGIN
matt_analysis_pkg.analyze_sql(p_sql =>
'WITH oel AS ( SELECT *
FROM oe_order_lines
WHERE ship_from_org_id = 88 )
SELECT oel.line_id, msi.segment1
FROM oel INNER JOIN mtl_system_items msi
ON msi.organization_id = 92 and msi.inventory_item_id = oel.inventory_item_id');
END;
/
Objects referenced by current SQL:
APPS.MTL_SYSTEM_ITEMS (SYNONYM)
APPS.OE_ORDER_LINES (SYNONYM)
The example (below) just reports the 1st level of dependencies. You could use DBA_DEPENDENCIES recursively to get more depth. Also, this version just writes to DBMS_OUTPUT.
As others have reported, just because a SQL depends on an object doesn't mean Oracle will actually access that object at run-time. Still, I think this is pretty close to what you were asking for.
Also, I noticed you tagged your question with Oracle 10g. I think the only thing in my solution that won't work in 10g is my direct access of a sequence. You'll have to replace that part with SELECT ... INTO to get the current sequence value.
Anyway, here is the source code for it (Oracle 12c):
-- This table doesn't do anything other than have a FGA policy on it.
CREATE TABLE matt_analysis_tab ( dummy varchar2(1) );
INSERT INTO matt_analysis_tab (dummy) VALUES ('X');
-- Sequence so we can create unique view names, in case two people analyze at the same time.
CREATE SEQUENCE matt_analysis_view_s;
-- Package to do the work.
CREATE OR REPLACE PACKAGE matt_analysis_pkg IS
PROCEDURE analyze_sql ( p_sql CLOB );
PROCEDURE analyze_current_sql (schema_name VARCHAR2, table_name VARCHAR2, policy_name VARCHAR2);
END matt_analysis_pkg;
/
CREATE OR REPLACE PACKAGE BODY matt_analysis_pkg AS
PROCEDURE analyze_sql (p_sql CLOB) IS
l_modified_sql CLOB := 'WITH v1$ AS ( SELECT /*+ MATERIALIZE */ dummy FROM matt_analysis_tab ) SELECT v1$.dummy, v2$.* FROM v1$, ( ' || p_sql || ') v2$';
BEGIN
DBMS_OUTPUT.PUT_LINE('l_modified_sql := ' || l_modified_sql);
EXECUTE IMMEDIATE l_modified_sql;
END analyze_sql;
PROCEDURE analyze_current_sql (schema_name VARCHAR2, table_name VARCHAR2, policy_name VARCHAR2) IS
PRAGMA AUTONOMOUS_TRANSACTION;
l_sql CLOB;
l_column_count INTEGER;
l_view_name VARCHAR2(30);
l_view_columns VARCHAR2(4000);
BEGIN
l_sql := SYS_CONTEXT ('userenv', 'CURRENT_SQL',4000)
|| SYS_CONTEXT ('userenv', 'CURRENT_SQL1',4000)
|| SYS_CONTEXT ('userenv', 'CURRENT_SQL2',4000)
|| SYS_CONTEXT ('userenv', 'CURRENT_SQL3',4000)
|| SYS_CONTEXT ('userenv', 'CURRENT_SQL4',4000)
|| SYS_CONTEXT ('userenv', 'CURRENT_SQL5',4000)
|| SYS_CONTEXT ('userenv', 'CURRENT_SQL6',4000)
|| SYS_CONTEXT ('userenv', 'CURRENT_SQL7',4000)
;
DBMS_OUTPUT.put_line ('Current SQL: ' || l_sql);
DBMS_OUTPUT.put_line ('Current SQL length (calc): ' || length(l_sql));
DBMS_OUTPUT.put_line ('Current SQL length (userenv): ' || SYS_CONTEXT('userenv','CURRENT_SQL_LENGTH'));
-- Parse the SQL to get the column count
DECLARE
l_cursor INTEGER;
l_column_descriptions SYS.DBMS_SQL.desc_tab;
BEGIN
l_cursor := sys.DBMS_SQL.open_cursor;
-- parse SQL
sys.DBMS_SQL.parse (c => l_cursor, statement => l_sql, language_flag => sys.DBMS_SQL.native);
-- Describe columns
sys.DBMS_SQL.describe_columns (c => l_cursor, col_cnt => l_column_count, desc_t => l_column_descriptions);
sys.DBMS_SQL.close_cursor (l_cursor);
END;
DBMS_OUTPUT.PUT_LINE('Column count = ' || l_column_count);
-- Build view columns. We need to do this because the column names in the SQL are not necessarily unique.
SELECT listagg('C' || lpad(rownum,4,'0'),',') within group ( order by rownum )
INTO l_view_columns
FROM dual
CONNECT BY rownum <= l_column_count;
DBMS_OUTPUT.PUT_LINE('l_view_columns = ' || l_view_columns);
l_view_name := 'matt_analysis_view_' || lpad(matt_analysis_view_s.nextval,6,'0') || '$';
DBMS_OUTPUT.PUT_LINE('l_view_name = ' || l_view_name);
l_sql := 'CREATE OR REPLACE FORCE VIEW ' || l_view_name || ' (' || l_view_columns || ') AS ' || l_sql;
EXECUTE IMMEDIATE l_sql;
DBMS_OUTPUT.PUT_LINE('Objects referenced by current SQL: ');
FOR r IN ( select referenced_owner || '.' || referenced_name || ' (' || referenced_type || ')' reference_info
from user_dependencies where name = upper(l_view_name)
AND referenced_name not like 'MATT_ANALYSIS%' ) LOOP
DBMS_OUTPUT.PUT_LINE(r.reference_info);
END LOOP;
EXECUTE IMMEDIATE 'DROP VIEW ' || l_view_name;
COMMIT;
END analyze_current_sql;
END matt_analysis_pkg;
/
-- Create the FGA policy
BEGIN
DBMS_FGA.add_policy (
object_schema => NULL, -- My current schema
object_name => 'MATT_ANALYSIS_TAB',
policy_name => 'MATT_ANALYSIS_POLICY',
audit_condition => NULL,
audit_column => NULL,
handler_schema => NULL, -- My current schema
handler_module => 'matt_analysis_pkg.analyze_current_sql',
enable => TRUE);
END;
/
-- Script to drop the policy, just in case
--EXEC DBMS_FGA.drop_policy (NULL, 'MATT_ANALYSIS_TAB', 'MATT_ANALYSIS_POLICY');
I am still waiting for the solution, but, for now, I came up with a quick and dirty way to get the table names along with aliases using the following python.
from copy import deepcopy
import cx_Oracle
############################################################################
####################### Database connection instantiation###################
############################################################################
#connObj = pyodbc.connect(connString,autocommit=True)
qry = """
Select name,userid,url,address_line_1 from user join address on
user.user_id = address.user_id where userid = 'xxyy'
"""
def getConn():
connObj = cx_Oracle.connect('asap', 'sdfssa', cx_Oracle.makedsn('DBLDEV03', 1521, '23432'))
return connObj
def destroy(connObj):
connObj.commit()
connObj.close()
del connObj
##################### Logic ########################################
import datetime
def getTablesFromQuery(qry):
listTables = []
listAliases = []
connObj = getConn()
cursor = connObj.cursor()
listSpaceItems = qry.split(" ")
found =False
for spaceItem in listSpaceItems:
if spaceItem != '' and spaceItem!='\n':
spaceItem = spaceItem.replace("\n",'')
listCommaItems = spaceItem.split(",")
if found == True:
##### We are assuming that the next item is always alias, the sql query should follow that rule to
##### get the aliases properly.
listAliases.append(spaceItem)
found = False
for commaItem in listCommaItems:
if commaItem != '':
item = commaItem
if "." in commaItem:
item=commaItem.split(".")[1]
cursor.execute('select * from all_tables where table_name=\''+item.upper()+'\'')
res = cursor.fetchall()
if res is not None and res.__len__()>0:
listTables.append(commaItem)
found = True
destroy(connObj)
return listTables,listAliases
try:
listTables, listAliases = getTablesFromQuery(qry)
for item in listTables:
print(''+item)
except:
print('Exception..')
############################################################################
####################### close database connection###########################
############################################################################
You could create a package procedure to accept a SQL statement as input. What it would do is wrap the SQL in a CREATE VIEW and then analyze the dependencies of the resulting view.
Here is the source code.
CREATE OR REPLACE PACKAGE matt_analysis_pkg IS
PROCEDURE analyze_sql ( p_sql CLOB );
END matt_analysis_pkg;
/
CREATE OR REPLACE PACKAGE BODY matt_analysis_pkg AS
PROCEDURE analyze_sql (p_sql CLOB) IS
PRAGMA AUTONOMOUS_TRANSACTION;
l_sql CLOB;
l_column_count INTEGER;
l_view_name VARCHAR2(30);
l_view_columns VARCHAR2(4000);
BEGIN
DBMS_OUTPUT.put_line ('Current SQL: ' || p_sql);
-- Parse the SQL to get the column count
DECLARE
l_cursor INTEGER;
l_column_descriptions SYS.DBMS_SQL.desc_tab;
BEGIN
l_cursor := sys.DBMS_SQL.open_cursor;
-- parse SQL
sys.DBMS_SQL.parse (c => l_cursor, statement => p_sql, language_flag => sys.DBMS_SQL.native);
-- Describe columns
sys.DBMS_SQL.describe_columns (c => l_cursor, col_cnt => l_column_count, desc_t => l_column_descriptions);
sys.DBMS_SQL.close_cursor (l_cursor);
END;
DBMS_OUTPUT.PUT_LINE('Column count = ' || l_column_count);
-- Build view columns. We need to do this because the column names in the SQL are not necessarily unique.
SELECT listagg('C' || lpad(rownum,4,'0'),',') within group ( order by rownum )
INTO l_view_columns
FROM dual
CONNECT BY rownum <= l_column_count;
DBMS_OUTPUT.PUT_LINE('l_view_columns = ' || l_view_columns);
l_view_name := 'matt_analysis_view_' || lpad(matt_analysis_view_s.nextval,6,'0') || '$';
DBMS_OUTPUT.PUT_LINE('l_view_name = ' || l_view_name);
l_sql := 'CREATE OR REPLACE FORCE VIEW ' || l_view_name || ' (' || l_view_columns || ') AS ' || p_sql;
EXECUTE IMMEDIATE l_sql;
DBMS_OUTPUT.PUT_LINE('Objects referenced by current SQL: ');
FOR r IN ( select referenced_owner || '.' || referenced_name || ' (' || referenced_type || ')' reference_info
from user_dependencies where name = upper(l_view_name)
AND referenced_name not like 'MATT_ANALYSIS%' ) LOOP
DBMS_OUTPUT.PUT_LINE(r.reference_info);
END LOOP;
EXECUTE IMMEDIATE 'DROP VIEW ' || l_view_name;
COMMIT;
END analyze_sql;
END matt_analysis_pkg;
/
Tester
BEGIN
matt_analysis_pkg.analyze_sql(p_sql =>
'WITH oel AS ( SELECT *
FROM oe_order_lines
WHERE ship_from_org_id = 88 )
SELECT oel.line_id, msi.segment1
FROM oel INNER JOIN mtl_system_items msi
ON msi.organization_id = 92 and msi.inventory_item_id = oel.inventory_item_id');
END;
Objects referenced by current SQL:
APPS.MTL_SYSTEM_ITEMS (SYNONYM)
APPS.OE_ORDER_LINES (SYNONYM)

need to modify the below oracle query

I have the below script , i want to modify it such a way lets say if it is executed first time then it will create the column but lets say if it is executed second time then it will show fail message which is not correct it should show the message that column is created and also if there comes any exception lets say column i s not created due to some technical exception then it should show fail message , please advise how to achieve this
SELECT COUNT(*) INTO L_COL_EXISTS FROM USER_TAB_COLS WHERE COLUMN_NAME = 'TOR' and TABLE_NAME='AVOICE';
IF L_COL_EXISTS = 1
THEN
outcome := 'Success';
ELSE
outcome := 'Fail';
END IF;
DBMS_OUTPUT.PUT_LINE(outcome);
folks please advise
I suppose it can help you
CREATE OR REPLACE PROCEDURE add_column
(
v_table_name IN VARCHAR2,
v_column_name IN VARCHAR2,
v_column_type IN VARCHAR2
)
IS
v_column_exists pls_integer;
v_ddl_str varchar2(1024);
BEGIN
BEGIN
SELECT count(*)
INTO v_column_exists
FROM user_tab_columns
WHERE table_name = upper(v_table_name)
and column_name = upper(v_column_name);
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
if v_column_exists = 0 then
v_ddl_str := 'alter table ' || v_table_name || ' add ( ' || v_column_name || ' ' || v_column_type || ')';
BEGIN
EXECUTE IMMEDIATE alter_str;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line ('something wrong');
RAISE;
END;
ELSE
dbms_output.put_line ('Column exists');
END IF;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END add_column;
/

Difference between EXEC_SQL, EXECUTE IMMEDIATE, DBMS_SQL and inline SQL

I've been going over some PL/SQL (In Oracle SQL Developer), and have seen several different formats of SQL being called.
For the consistency and speed of current and future code, I'd like to know which is the preferred choice.
There are four types I've seen.
1) Plain DDL:
CREATE TABLE newtable AS SELECT * FROM pSource;
2) Execute Immediate (Native Dynamic SQL):
statement := 'CREATE TABLE newtable AS SELECT * FROM ' || pSource;
EXECUTE IMMEDIATE statement;
3) EXEC_SQL:
EXEC_SQL('CREATE TABLE newtable AS SELECT * FROM ' || pSource);
4) DBMS_SQL:
cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cursor, 'CREATE TABLE newtable AS SELECT * FROM ' || pSource, DBMS_SQL.NATIVE);
numRows := DBMS_SQL.EXECUTE(cursor);
Are there any particular advantages/disadvantages/restrictions between these different ways of calling?
1) You can't execute straight DDL inside of a PL/SQL block.
BEGIN
CREATE TABLE TEST AS (
SELECT * FROM FND_USER
);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
Yields:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
2) EXECUTE IMMEDIATE (and its sister DBMS_SQL) are used to execute SQL inside of a PL/SQL block. These differ from "regular" SQL in that they actually use a completely different SQL engine (in PL/SQL's case it runs in the oracle process) to compute. This is why so many of us preach "if you can do it in SQL don't do it in PL/SQL".
Even these two options differ between how. EXECUTE IMMEDIATE is quick and easy but kind of dumb. DBMS_SQL is a little more complex but gives the developer a lot more control.
For instance this example that essentially describes the columns of a table:
declare
c number;
d number;
col_cnt integer;
f boolean;
rec_tab dbms_sql.desc_tab;
col_num number;
procedure print_rec(rec in dbms_sql.desc_rec) is
begin
dbms_output.new_line;
dbms_output.put_line('col_type = '
|| rec.col_type);
dbms_output.put_line('col_maxlen = '
|| rec.col_max_len);
dbms_output.put_line('col_name = '
|| rec.col_name);
dbms_output.put_line('col_name_len = '
|| rec.col_name_len);
dbms_output.put_line('col_schema_name = '
|| rec.col_schema_name);
dbms_output.put_line('col_schema_name_len = '
|| rec.col_schema_name_len);
dbms_output.put_line('col_precision = '
|| rec.col_precision);
dbms_output.put_line('col_scale = '
|| rec.col_scale);
dbms_output.put('col_null_ok = ');
if (rec.col_null_ok) then
dbms_output.put_line('true');
else
dbms_output.put_line('false');
end if;
end;
begin
c := dbms_sql.open_cursor;
dbms_sql.parse(c, 'select * from fnd_user', dbms_sql.native);
d := dbms_sql.execute(c);
dbms_sql.describe_columns(c, col_cnt, rec_tab);
/*
* Following loop could simply be for j in 1..col_cnt loop.
* Here we are simply illustrating some of the PL/SQL table
* features.
*/
col_num := rec_tab.first;
if (col_num is not null) then
loop
print_rec(rec_tab(col_num));
col_num := rec_tab.next(col_num);
exit when (col_num is null);
end loop;
end if;
dbms_sql.close_cursor(c);
end;
/
Source
Since DBMS_SQL allows us to open and manipulate the cursor in which the PL/SQL block is operating inside of the result would be very difficult to reproduce in an EXECUTE IMMEDIATE block (difficulty level: no selecting from ALL_TAB_COLS this is just meant to be informative:).
3)EXEC_SQL is a forms specific version of the above DBMS_SQL. Use it wisely. :)
Here is a great breakdown of the above and here is Tom Kyte breaking it down like only he can.

Resources