How to use "Where" clause in Oracle database (stored procedures) - sql

I am using the following stored procedures in an Oracle database to export the output of the query to a CSV file.
CREATE OR REPLACE PROCEDURE run_query(p_tbl_name IN VARCHAR2
) IS
Select_Stmt VARCHAR2(100) := 'select * from '||p_tbl_name;
p_dir VARCHAR2 (100) := 'DATA_PUMP_DIR';
v_finaltxt VARCHAR2(4000);
v_v_val VARCHAR2(4000);
v_n_val NUMBER;
v_d_val DATE;
v_ret NUMBER;
c NUMBER;
d NUMBER;
col_cnt INTEGER;
f BOOLEAN;
rec_tab DBMS_SQL.DESC_TAB;
col_num NUMBER;
v_fh UTL_FILE.FILE_TYPE;
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(c, Select_Stmt, DBMS_SQL.NATIVE);
d := DBMS_SQL.EXECUTE(c);
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
FOR j in 1..col_cnt
LOOP
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000);
WHEN 2 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_n_val);
WHEN 3 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_d_val);
ELSE
DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000);
END CASE;
END LOOP;
-- This part outputs the HEADER
v_fh := UTL_FILE.FOPEN(upper(p_dir),p_tbl_name||'.csv','w',32767);
FOR j in 1..col_cnt
LOOP
v_finaltxt := ltrim(v_finaltxt||','||lower(rec_tab(j).col_name),',');
END LOOP;
UTL_FILE.PUT_LINE(v_fh, v_finaltxt);
-- This part outputs the DATA
LOOP
v_ret := DBMS_SQL.FETCH_ROWS(c);
EXIT WHEN v_ret = 0;
v_finaltxt := NULL;
FOR j in 1..col_cnt
LOOP
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
v_finaltxt := ltrim(v_finaltxt||',"'||v_v_val||'"',',');
WHEN 2 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_n_val);
v_finaltxt := ltrim(v_finaltxt||','||v_n_val,',');
WHEN 3 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_d_val);
v_finaltxt := ltrim(v_finaltxt||','||to_char(v_d_val,'DD/MM/YYYY HH24:MI:SS'),',');
ELSE
DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
v_finaltxt := ltrim(v_finaltxt||',"'||v_v_val||'"',',');
END CASE;
END LOOP;
-- DBMS_OUTPUT.PUT_LINE(v_finaltxt);
UTL_FILE.PUT_LINE(v_fh, v_finaltxt);
END LOOP;
UTL_FILE.FCLOSE(v_fh);
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
The above stored procedure is working perfectly and I got the output by using the following script to run this stored procedure
exec run_query person_list;
Here stored_procedure_name is run_query and the table_name is person_list.
Now my question is that how can I use the WHERE clause after the select statement on "line 3" -
Select_Stmt VARCHAR2(100) := 'select * from '||p_tbl_name;
or are there any other ways I can use the where clause.
Thanks in advance.

Select_Stmt VARCHAR2(100) := 'select * from '||p_tbl_name||' where name=''david''';
You have to have the character delimiters; and since you have it inside quotes you have to duplicate them.

Related

DBMS_LOB.APPEND File is getting cut because of concatenation

I have the below block. I want to replace that concatenation and also have a records from the cursor in new line.
For small data set it works,but when the number of rows returned by the cursor is 600+ it cuts the file. I think its because of conversion of CLOB to Varchar2 when || is used.
How do I resolve it?
DECLARE
CURSOR cur IS
SELECT ID, CA_ID, STATUS,S_DATE, E_DATE FROM TEST; -- Here I have a big query
v_MESG CLOB := EMPTY_CLOB();
v_Interim CLOB := EMPTY_CLOB();
v_col VARCHAR2(500);
CRLF VARCHAR2(2) := CHR(13)||CHR(10);
v_fileHandler UTL_FILE.FILE_TYPE;
BEGIN
v_col:= '"ID","CA_ID","Status","S_Date","E_Date"'||CRLF;
dbms_lob.createtemporary(v_MESG, TRUE);
FOR v_cur IN cur LOOP
BEGIN
v_Interim := NULL;
v_Interim:= v_col||v_cur.ID||',"'||
v_cur.CA_ID||'","'||
v_cur.Status||'","'||
v_cur.S_Date||'","'||
v_cur.E_DATE||'"'||CRLF
;
DBMS_LOB.APPEND(v_mesg, v_Interim);
v_col := NULL;
END;
END LOOP;
v_fileHandler := UTL_FILE.FOPEN('XML_PROCESS_TEST',v_file_name , 'w');
UTL_FILE.PUT(v_fileHandler, v_MESG);
UTL_FILE.FCLOSE(v_fileHandler);
END;

dbms_output.put_line write out each value from function

I've got a function that takes three number arguments and returns a value calculated from those three numbers. Now in another stored procedure I call try to write out each value like this:
CREATE OR REPLACE PROCEDURE P_POOL
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('test'||' '||POOL_PKG.F_REKTANGULÄR(6,4,2);
But I want to the output to be example:
test is 6 meter and 4 meter and 2 meter!
How can I add text after each value?
Try this
Package POOL_PKG
IS
FUNCTION F_REKTANGULÄR(meter_in NUMBER,height_in NUMBER,bottom_in NUMBER,Show_dims_in IN NUMBER := 0) RETURN NUMBER;
END POOL_PKG;
Package Body POOL_PKG is
FUNCTION F_REKTANGULÄR(meter_in NUMBER,height_in NUMBER,bottom_in NUMBER, Show_dims_in IN NUMBER := 0) RETURN NUMBER
v_result NUMBER(10);
v_unit VARCHAR2(10) := 'meter';
IS
--assert that all inputs are greater than 0
--and less than a reasonable amount
v_result := meter_in * height_in * bottom_in;
IF show_dims_in = 1
THEN
DBMS_OUTPUT(meter_in ||' '||v_unit||', '||height_in||' '||v_unit||', '||bottom_in);
END IF;
RETURN v_result;
END F_REKTANGULÄR;
END POOL_PKG;
and could be used this way
DECLARE
v_result NUMBER(9);
BEGIN
v_result := POOL_PKG.F_REKTANGULÄR(6 ,4 ,2,1);
END;
Or, given your comments this would work to:
Declare
a NUMBER(9);
b NUMBER(9);
c NUMBER(9);
v_unit VARCHAR2(10) := 'meter';
v_result NUMBER(9);
BEGIN
a := 6;
b := 4;
c := 2;
DBMS_OUTPUT(a||' '||v_unit||', '||b||' '||v_unit||', '||c||' '||v_unit);
v_result := POOL_PKG.F_REKTANGULÄR(a ,b ,c);
END;

Splitting string in oracle - fastest way

Does anybody know how to split string separated by ';' in a trigger, faster than this code:
SELECT regexp_substr('asd;asaaaad;dd;', '([^;]*)(;)', 1, level, null, 1)
BULK COLLECT INTO array_TREATMENT_TR_CD
FROM DUAL
CONNECT BY LEVEL < REGEXP_COUNT('asd;asaaaad;dd;', '[;]') + 1 ;
Regexp functions are usually way slower than standard db functions. When I run your code 100.000 times it takes around 12 seconds (on my db, YMMV).
Then I created this small test:
declare
type t_vc2 is table of varchar2(250) index by pls_integer;
procedure split_str(
p_str1 in out nocopy varchar2
, p_str2 out varchar2
, p_separator in varchar2 default ';'
)
is
l_pos pls_integer;
begin
l_pos := instr(p_str1, p_separator);
if nvl(l_pos, 0) = 0
then
p_str2 := p_str1;
p_str1 := null;
else
p_str2 := substr(p_str1, 1, l_pos-1);
p_str1 := substr(p_str1, l_pos+1);
end if;
end split_str;
begin
for l_i in 1 .. 1000000
loop
declare
array_TREATMENT_TR_CD t_vc2;
l_input varchar2(250);
l_return varchar2(250);
begin
l_input := 'asd;asaaaad;dd;';
loop
split_str(l_input, l_return);
if l_return is not null
then
array_TREATMENT_TR_CD(array_TREATMENT_TR_CD.count+1) := l_return;
end if;
exit when l_return is null;
end loop;
end;
end loop;
end;
/
This parses your example string 100.000 times to an array with standard db functions. It takes around 0.5 seconds. That's a significant improvement if "real time" is what you aim for.

Dynamically Identify Table (Table Identified by Variable)

I'm trying to create a procedure that will allow me to write an existing row to another table dynamically but the row declaration and insert-statement in the following snippet don't work. The error message indicates that the view hasn't been identified although outputting the target_table.table_name works just fine.
More will be added to the block later on - such as a column with the operation (e.g. INSERT or UPDATE). This is just a simple example and the last procedure (pass_reference) is used to trigger the procedure.
Any help would be much appreciated.
CREATE OR REPLACE PROCEDURE denormalize (new_cursor sys_refcursor, target_table_name varchar)
IS
target_table user_tables%rowtype;
sql_target_table varchar(200) := 'select * from user_tables where table_name = :target_table_name';
row target_table%rowtype;
BEGIN
execute immediate sql_target_table into target_table using target_table_name;
LOOP
fetch new_cursor into row;
exit when new_cursor%notfound;
insert into target_table values row;
commit;
END LOOP;
END denormalize;
/
CREATE OR REPLACE PROCEDURE pass_reference
AS
new_cursor sys_refcursor;
BEGIN
open new_cursor for select * from sales where sales_id=1;
denormalize(new_cursor, 'NEW_SALES');
END;
/
please check this code, it's not working only as for example, as you see for working columns in your cursor should be named as columns in destination table.
I take this code from package that create html table in mail base on view, hope you found this example useful
good luck
declare
in_view_name varchar2(30);
in_table_name varchar2(30) := 'your_new_table';
out_rc number;
out_rc_txt varchar2(1000);
l_cursor number;
l_sql varchar2(50) := 'select * from ' || in_view_name;
l_col_cnt binary_integer;
l_col_tab dbms_sql.desc_tab;
l_column_value varchar2(4000);
l_is_empty boolean := true;
l_insert_header varchar2(1000);
l_insert varchar2(32000);
begin
out_rc := 0;
out_rc_txt := 'OK';
l_cursor := dbms_sql.open_cursor;
dbms_sql.parse(l_cursor, l_sql, dbms_sql.native);
l_col_cnt := dbms_sql.execute(l_cursor);
dbms_sql.describe_columns(l_cursor, l_col_cnt, l_col_tab);
l_insert_header := 'insert into '||in_table_name||'(';
if l_col_cnt > 0 then
-- header
for i in l_col_tab.first .. l_col_tab.last loop
dbms_lob.append(l_insert_header, l_col_tab(i).col_name);
if i != l_col_tab.last then
dbms_lob.append(l_insert_header, ',');
end if;
dbms_sql.define_column(l_cursor, i, l_column_value, 4000);
end loop;
l_insert_header := l_insert_header || ') values(';
-- data
while dbms_sql.fetch_rows(l_cursor) > 0 loop
l_is_empty := false;
l_insert := l_insert_header;
for i in l_col_tab.first .. l_col_tab.last loop
dbms_sql.column_value(l_cursor, i, l_column_value);
l_insert := l_insert || '''' || l_column_value || ''','
if not in_attachment then
dbms_lob.append(out_table, l_td);
end if;
if (not in_attachment) or (l_column_value is not null) then
dbms_lob.append(out_table, nvl(l_column_value, l_nbsp));
end if;
if (not in_attachment) or (i != l_col_tab.last) then
dbms_lob.append(out_table, l_tdc);
end if;
end loop;
l_insert := substr(l_insert, 1, length(l_insert) - 1) || ')';
execute immediate l_insert;
end loop;
end if;
dbms_sql.close_cursor(l_cursor);
end;

A procedure to Reverse a String in PL/SQL

I just started learning PL/SQL and I'm not sure how to create a procedure. The logic seems about right but I think there's some syntactical mistake in the first line. Here's my code:-
CREATE OR REPLACE PROCEDURE ReverseOf(input IN varchar2(50)) IS
DECLARE
reverse varchar2(50);
BEGIN
FOR i in reverse 1..length(input) LOOP
reverse := reverse||''||substr(input, i, 1);
END LOOP;
dbms_output.put_line(reverse);
END;
/
Two things - you shouldn't specify the datatype size in procedure's/function's parameter list and you do not need the DECLARE keyword. Try this:
CREATE OR REPLACE PROCEDURE ReverseOf(input IN varchar2) IS
rev varchar2(50):='';
BEGIN
FOR i in reverse 1..length(input) LOOP
rev := rev||substr(input, i, 1);
END LOOP;
dbms_output.put_line(rev);
END;
Try it without PL/SQL!
WITH
params AS
(SELECT 'supercalifragilisticexpialidocious' phrase FROM dual),
WordReverse (inpt, outpt) AS
(SELECT phrase inpt, CAST(NULL AS varchar2(4000)) outpt FROM params
UNION ALL
SELECT substr(inpt,2,LENGTH(inpt)-1), substr(inpt,1,1) || outpt
FROM wordReverse
WHERE LENGTH(inpt) > 0
)
SELECT phrase,outpt AS reversed FROM wordReverse, params
WHERE LENGTH(outpt) = LENGTH(phrase) ;
PHRASE REVERSED
---------------------------------- -----------------------------------
supercalifragilisticexpialidocious suoicodilaipxecitsiligarfilacrepus
Citation: http://rdbms-insight.com/wp/?p=94
Another solution reverse string minimizing loop count
DECLARE
v_str VARCHAR2(100) DEFAULT 'MYSTRING';
v_len NUMBER;
v_left VARCHAR2(100);
v_right VARCHAR2(100);
BEGIN
v_len := LENGTH(v_str)/2;
FOR rec IN 1..v_len
LOOP
v_left := substr(v_str,rec,1) || v_left;
IF rec * 2 <= LENGTH(v_str) THEN
v_right := v_right || substr(v_str,-rec,1);
END IF;
END LOOP;
v_str := v_right || v_left;
dbms_output.put_line(v_str);
END;
set serveroutput on
declare
str1 varchar2(30);
len number(3);
str2 varchar2(30);
i number(3);
begin
str1:='&str1';
len:=length(str1);
for i in reverse 1..len
loop
str2:=str2 || substr(str1,i,1);
end loop;
dbms_output.put_line('Reverse string is: '||str2);
end;
/
create or replace procedure ap_reverse_number(input_no VARCHAR2) as
output_no VARCHAR2(100);
begin
for i in 1 .. length(input_no) loop
output_no := output_no || '' ||
substr(input_no, (length(input_no) - i + 1), 1);
end loop;
dbms_output.put_line('Input no. is :' || input_no);
dbms_output.put_line('Output no. is:' || output_no);
end;
This should do the job correctly.
Try this one line statement to reverse the string in sql
with a as (select 'brahma' k from dual)
select listagg(substr(k,length(k)-level+1,1),'') within group (order by 1) b from a connect by level<length(k)+1
Try this one line query to reverse a string or a number.
select reverse('HelloWorld') from dual;
declare
name varchar2(20):='&name';
rname varchar2(20);
begin
for i in reverse 1..length(name)
loop
rname:=rname||substr(name,i,1);
end loop;
display(rname);
end;