Parse a parameter to a view from a SP in Oracle 10g - oracle

I have created a VIEW by joining some number of tables. I used a SP to call that VIEW and in the SP I'm filtering the data set of the view using an ID. Now I need to pass this ID to VIEW and do the filtering inside the VIEW itself. What is the way of passing this ID as a parameter to view in Oracle 10g?
Current View
CREATE OR REPLACE FORCE VIEW "MY_VIEW"
//SELECT statements goes here
FROM MY_TABLE_1, MY_TABLE_2
//TABLE JOINS
where
//FILTERS
Current Stored Procedure
CREATE OR REPLACE PROCEDURE MY_SP
(
REQUESTACCOUNTID IN NUMBER
, p_cursor out SYS_REFCURSOR
) AS
internal_flag NUMBER;
BEGIN
open p_cursor for
SELECT //SELECT THE COLUMNS
from MY_VIEW my
WHERE my.account_id = REQUESTACCOUNTID;
END MY_SP;
What I need to do is, parse the parameter REQUESTACCOUNTID to the view while selecting

this is sorted out using a package variable. More explanation can be found using this URL

Related

Inserting new JSON document into Oracle Autonomous JSON Database

With Database Actions (SQL Developer Web), it's quite easy to click on the 'New JSON Document' button to add a new JSON document to the collection.
The collection of course is actually a table in Oracle, and the table itself has a number of columns:
I have created modules in ORDS with PL/SQL handlers. While I am able to update JSON documents here by using
UPDATE "Collection" SET json_document = '{"key": "value"}' WHERE JSON_VALUE(json_document, '$.id') = :id'
I am not able to add a new document easily with
INSERT INTO "Collection" (json_document) VALUES ('{"key": "value"}')
because the id is set as a PK column and must be specified. How might I use PL/SQL to add a new document with auto generated fields elsewhere? Or should I use SODA for PL/SQL to achieve this only?
Thanks!
You use the dbms_soda package to access the collection. Then use the methods on soda_colletion_t to manipulate it.
For example:
soda create students;
declare
collection soda_collection_t;
document soda_document_t;
status number;
begin
-- open the collection
collection := dbms_soda.open_collection('students');
document := soda_document_t(
b_content => utl_raw.cast_to_raw (
'{"id":1,"name":"John Blaha","class":"1980","courses":["c1","c2"]}'
)
);
-- insert a document
status := collection.insert_one(document);
end;
/
select * from students;
ID CREATED_ON LAST_MODIFIED VERSION JSON_DOCUMENT
-------------------------------- ------------------------ ------------------------ -------------------------------- ---------------
A92F68753B384F87BF12557AC38098CB 2021-12-22T14:15:12.831Z 2021-12-22T14:15:12.831Z FE8C80FED46A4F18BFA070EF46073F43 [object Object]
For full documentation and examples on how to use SODA for PL/SQL, see here.

Oracle substitutes asterisk to all columns in a view

I've just bumped into the case when I have a view that has an asterisk reference to one of underlying tables. After compilation this asterisk sign is being exchanged to all column list and I don't want it to happen. See example below:
create or replace view test_view_cols as
select 1 f_1,
2 f_2,
3 f_3
from dual
/
create or replace view test_interface as
select d.*
from test_view_cols d
/
create or replace view test_view_cols as
select 1 f_1,
2 f_2,
3 f_3,
4 f_4,
5 f_5
from dual
/
select count(*) col_cnt -- returns 3 and not 5
from user_tab_cols s
where s.TABLE_NAME = 'TEST_INTERFACE';
select s.text
from user_views s
where s.VIEW_NAME = 'TEST_INTERFACE'
/* returns
select d."F_1",d."F_2",d."F_3"
from test_view_cols d
*/
But I don't want asterisk to be exchanged and I want have all the columns from test_view_cols in test_interface view.
Can I somehow force Oracle to keep an asterisk in an underlying query?
Oracle 11gR2
No.
You can't define a view that returns a variable number of columns depending on the changing definition of an underlying object (whether that underlying object is a table or a view). You could define a stored procedure that has an OUT parameter of type SYS_REFCURSOR that would return whatever columns are in the underlying object. You should also be able to define a pipelined table function that returns a different number of columns based on the underlying object-- that does get much easier in more recent versions, though.
You need after each change of the underlining object simple re-create the interface view as well.
create or replace view test_interface as
select d.*
from test_view_cols d
Than is the view definition again adjusted to the new object. The start * is expanded in the view compilation not in the query.
What you can use starting with Oracle 19c (or better 21c) is SQL Macro
The TABLE SQL Macros are defined similar as function, but they return text of the subquery that will be used.
You can define the SQL Macro that returns all columns of the base view as follows
create or replace function test_interface
return varchar2 SQL_MACRO
is
begin
return q'[
select * from test_view_cols]';
end;
/
You use the SQL Macro in the FROM clause
select * from test_interface();
This query return on the first run the three columns of the underlining view.
After the view is modified, you get back the five columns. Why?
The SQL Macro is activated only at parse time, so you should take some care, that you do not get the old columns state from the cached cursor.
But this is not a problem, because by changing the underlining view your cursor is automatically invalidated and must be reparsed with the new definition.
But SQL Macros are even more powerful. You can define one universal interface SQL Macro that can be applied on all your tested objects by passing the name of the underlining view or table as a parameter:
create function my_interface (t DBMS_TF.Table_t)
return varchar2 SQL_MACRO(TABLE)
is
begin
return q'[
select * from t]';
end;
/
In the query you than pass the name of the tested view
select * from my_interface(test_view_cols);
More information and examples of SQL Macros can be found here and there.

PL/SQL reusable dynamic sql program for same type of task but different table and column

Thank you for reply guys. I kind of solved my problem.
I used to try to update data with ref cursor in dynamic SQL using "where current of" but I now know that won't work.
Then I tried to use %rowtype to store both 'id' and 'clob' in one variable for future updating but turns out weak ref cursor can't use that type binding either.
After that I tried to use record as return of an ref cursor and that doesn't work on weak cursor either.
On the end, I created another cursor to retrieve 'id' separately along with cursor to retrieve 'clob' on the same time then update table with that id.
I'm now working on a Oracle data cleaning task and have a requirement like below:
There are 38 tables(maybe more in the future) and every table has one or multiple column which type is Clob. I need to find different keyword in those columns and according to a logic return binary label of the column and store it in a new column.
For example, there is a table 'myTable1' which has 2 Clob columns 'clob1' and 'clob2'. I'd like to find keyword 'sky' from those columns and store '0'(if not found) or '1'(if found) in two new columns 'clob1Sky','clob2Sky'.
I know if I could write it on a static way which will provide higher efficiency but I have to modify it for those very similar tasks every time. I want save some time on this so I'm trying to write it in a reusable way and not binding to certain table.
But I met some problem when writing the program. My program is like below:
create or replace PACKAGE body LABELTARGETKEYWORD
as
/**
#param varcher tableName: the name of table I want to work on
#param varchar colName: the name of clob column
#param varchar targetWord: the word I want to find in the column
#param varchar newColName: the name of new column which store label of clob
*/
PROCEDURE mainProc(tableName varchar, colName varchar,targetWord varchar,newColName varchar2)
as
type c_RecordCur is ref cursor;
c_sRecordCur c_recordCur;
/*other variables*/
begin
/*(1) check whether column of newColName exist
(2) if not, alter add table of newColName
(3) open cursor for retrieving clob
(4) loop cursor
(5) update set the value in newColName accroding to func labelword return
(6) close cursor and commit*/
end mainProc;
function labelWord(sRecord VARCHAR2,targetWord varchar2) return boolean...
function ifColExist(tableName varchar2,newColName varchar2) return boolean...
END LABELTARGETKEYWORD;
Most DML and DDL are written in dynamic sql way.
The problem is when I write the (5) part, I notice 'Where current of' clause can not be used in a ref cursor or dynamic sql statement. So I have to change the plan.
I tried to use a record(rowid,label) to store result and alter the table later.(the table only be used by two people in my group, so there won't be problem of lock and data changes). But I find because I'm trying to use dynamic sql so actually I have to define ref cursor with return of certain %rowtype and basically all other variables, %type in dynamic sql statement. Which makes me feel my method has something wrong.
My question are:
If there a way to define %type in dynamic sql? Binding type to variable in dynamic SQL?
Could anybody give me a hint how to write that (5) part in dynamic SQL?
Should not I design my program like that?
Is it not the way how to use dynamic SQL or PLSQL?
I'm very new to PL/SQL. Thank you very much.
According to Tom Kyte's advice, to do it in one statement if it can be done in one statement, I'd try to use a single UPDATE statement first:
CREATE TABLE mytable1 (id NUMBER, clob1 CLOB,
clob2 CLOB, clob1sky NUMBER, clob2sky NUMBER )
LOB(clob1, clob2) STORE AS SECUREFILE (ENABLE STORAGE IN ROW);
INSERT INTO mytable1(id, clob1, clob2)
SELECT object_id, object_name, object_type FROM all_objects
WHERE rownum <= 10000;
CREATE OR REPLACE
PROCEDURE mainProc(tableName VARCHAR2, colName VARCHAR2, targetWord VARCHAR2, newColName VARCHAR2)
IS
stmt VARCHAR2(30000);
BEGIN
stmt := 'UPDATE '||tableName||' SET '||newColName||'=1 '||
'WHERE DBMS_LOB.INSTR('||colName||','''||targetWord||''')>1';
dbms_output.put_line(stmt);
EXECUTE IMMEDIATE stmt;
END mainProc;
/
So, calling it with mainProc('MYTABLE1', 'CLOB1', 'TAB', 'CLOB1SKY'); fires the statement
UPDATE MYTABLE1 SET CLOB1SKY=1 WHERE DBMS_LOB.INSTR(CLOB1,'TAB')>1
which seems to do the trick:
SELECT * FROM mytable1 WHERE clob1sky=1;
id clob1 clob2 clob1sky clob2skiy
33 I_TAB1 INDEX 1
88 NTAB$ TABLE 1
89 I_NTAB1 INDEX 1
90 I_NTAB2 INDEX 1
...
I am not sure with your question-
If this job is suppose to run on daily or hourly basis ,running query through it will be very costly. One thing you can do - put all your clob data in a file and save it in your server(i guess it must be linux). then you can create a shell script and schedule a job to run gerp command and fetch your required value and "if found then update your table".
I think you should approaches problem another way:
1. Find all columns that you need:
CURSOR k_clobs
select table_name, column_name from dba_tab_cols where data_type in ('CLOB','NCLOB');
Or 2 cursor(you can build you query if you have more than 1 CLOB per table:
CURSOR k_clobs_table
select DISTINCT table_name from dba_tab_cols where data_type in ('CLOB','NCLOB');
CURSOR k_clobs_columns(table_namee varchar(255)) is
select column_name from dba_tab_cols where data_type in ('CLOB','NCLOB') and table_name = table_namee;
Now you are 100% that column you are checking is clob, so you don't have to worry about data type ;)
I'm not sure what you want achieve, but i hope it may help you.

Oracle Datatype Modifier

I need to be able to reconstruct a table column by using the column data in DBA_TAB_COLUMNS, and so to develop this I need to understand what each column refers to. I'm looking to understand what DATA_TYPE_MOD is -- the documentation (http://docs.oracle.com/cd/B19306_01/server.102/b14237/statviews_2094.htm#I1020277) says it is a data type modifier, but I can't seem to find any columns with this field populated or any way to populate this field with a dummy column. Anyone familiar with this field?
Data_type_mod column of the [all][dba][user]_tab_columns data dictionary view gets populated when a column of a table is declared as a reference to an object type using REF datatype(contains object identifier(OID) of an object it points to).
create type obj as object(
item number
) ;
create table tb_1(
col ref obj
)
select t.table_name
, t.column_name
, t.data_type_mod
from user_tab_columns t
where t.table_name = 'TB_1'
Result:
table_name column_name data_type_mod
-----------------------------------------
TB_1 COL REF
Oracle has a PL/SQL package that can be used to generate the DDL for creating a table. You would probably be better off using this.
See GET_DDL on http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_metada.htm#i1019414
And see also:
How to get Oracle create table statement in SQL*Plus

Assign the output of a stored procedure to a Column

I'm executing a master stored procedure to load columns in to a target table.
I have a column called dptname - this column is handled by different project team so they have defined a child stored procedure all that will do is it will get an empno and output the Dptname. They requested us to call the below stored procedure to load my dptname column.
Could you please let me know how can I assign/call this child stored procedure and assign to the deptname column in my master stored procedure?
This is the skeleton of the child stored procedure:
get_dptname(in_emp_no, out_dptname)
My master stored procedure:
Create or Replace procedure InsertTargetTable
as
begin
for a in (
Select EMP.empno
EMP.NAME,
CL.Attendance,
DEPTNAME= "**ASSIGN THE VALUE FROM THE 3rd Party stored procedure**
from EMP, CL
on EMP.empno=CL.empno
) Loop
Insert Into Target Table ( empno, NAME,Attendance, DEPTNAME )
Values (a.empno, a.NAME, a.Attendance, a.DEPTNAME);
ENDLOOP;
COMMIT:
END
If the other group created a function GET_DEPT_NAME, then you could use it as follows:
CREATE OR REPLACE PROCEDURE InsertTargetTable
AS
BEGIN
INSERT INTO Target_Table ( empno, NAME, Attendance, DEPTNAME )
SELECT EMP.empno, EMP.NAME, CL.Attendance, GET_DEPT_NAME(EMP.empno)
FROM EMP, CL
WHERE EMP.empno = CL.empno;
COMMIT:
END;
A few notes:
The data is being de-normalizing: what if the employee changes departments? Your Target_Table won't be updated but will remain fixed at the department set during insert. Perhaps the department should be looked up when the table is actually queried in order to obtain the current department value.
Hopefully the stored proc is a function, then it can be used easily as shown in the example above. (If not, ask for a function).
Avoid looping if possible. A single "insert into ... select from" statement will be much more efficient.
You can use following query. Pass the DEPT_NO variable to stored procedure and since it is an OUT parameter you can access value from your master stored procedure.
GET_DPTNAME(IN_EMP_NO=>EMP_NO,OUT_DEPT_NO=>DEPT_NO);

Resources