Oracle - using bind variable in LIKE clause of dynamic cursor - oracle

I am using dynamic cursor for fetching data. Query that is being executed looks similar to:
query := 'SELECT column1, column2
FROM my_table
WHERE column1 LIKE ''%:bv1%''';
And the cursor itself is executed like this:
OPEN my_cursor FOR query USING my_var1;
I also tried to check the query and print it:
... WHERE column1 LIKE '%:bv1%' ...
so apostrophes are escaped, but the cursor fetches no data. Is it even possible to use bind variables in LIKE clause and if yes, what did I do wrong?

This is a subtle one. It's often useful to start with a static statement, get that right, then convert it to dynamic SQL.
In non-dynamic SQL we might do it like this:
SELECT column1, column2
FROM my_table
WHERE column1 LIKE '%' || local_var || '%';
The dynamic equivalent is
query := 'SELECT column1, column2
FROM my_table
WHERE column1 LIKE ''%''||:bv1||''%'' ';

Take the bind variable out of the string:
VARIABLE mycursor REFCURSOR;
VARIABLE bv1 VARCHAR2;
BEGIN
:bv1 := 'X'; -- set the bind variable
END;
/
DECLARE
query VARCHAR2(200) := 'SELECT * FROM DUAL WHERE DUMMY LIKE :value';
BEGIN
OPEN :mycursor FOR query USING '%' || :bv1 || '%';
END;
/
PRINT mycursor;
Output
MYCURSOR
--------
DUMMY
-----
X

Related

Query to dynamic sql

When try compaile my packages get error.
PLS-00306: wrong number or types of arguments in call to '||'
v_sql := 'select count(*) from table ('|| p_month_ids ||') where column_value = ' || p_month_id;
Execute Immediate v_sql into v_count;
You are trying to concatenate values into a string, but that can only work if each individual value is either a string or can be implicitly converted to a string. If p_month_ids is a collection - as it seems to be from how you're using it - then you would have to add each element individually - as you can't implicitly convert the p_month_ids collection to a string.
But don't do that; use bind variables:
v_sql := 'select count(*) from table (:p_month_ids) where column_value = :p_month_id';
execute immediate v_sql into v_count using p_month_ids, p_month_id;
Or don't use dynamic SQL at all:
select count(*) into v_count
from table (p_month_ids) where column_value = p_month_id;
Or loop over the collection and count matches directly, instead of using a query (and context switch).
db<>fiddle

how to update all columns of a table to uppercase?

there is a table with about 800 columns that I have to update to upper case, do you know a "quick" way to do it?
Maybe with PLSQL but I can't think of how to do it.
Thanks!
Probably something like this would work. Using xmlagg because listagg would run out of space. You could also do a PL/SQL loop over user_tab_columns for your table if you needed something more detailed.
declare
my_table varchar2(30) := 'TABLE1';
command clob;
begin
select to_clob('update ') || my_table || ' set '
|| rtrim(xmlagg(xmlelement(e,column_name || '=UPPER(' || column_name || '), ') order by column_id).extract('//text()').getclobval(),', ') as cols
into command
from user_tab_columns where table_name = my_table;
execute immediate command;
end;
/
Try running the select statement by itself first (with your table name, and no into) if you want to run the update statement yourself.

Create a delimited field when using a between to_date Oracle sqlplus

I am creating a csv file from a query using ! as a delimiter (I did not create the query and I cannot modify the delimiter).
I have to modify the select statement to use a between to_date but my procedure is dying. The query is assigned to a variable which is then passed into the procedure that is used to create the csv file.
I believe the error is happening because I'm delimiting the two dates when there is only supposed to be a single date column
This is the original code that works using a single date
CREATE OR REPLACE PROCEDURE my_procedure(
p_column1 IN VARCHAR2
,p_column2 IN VARCHAR2
)AS
v_query VARCHAR2(5000);
v_column1 VARCHAR2(10);
v_column2 VARCHAR2(10);
v_column1 := p_column1;
v_column2 := p_column2;
v_query := q'!
SELECT column1
FROM mytable
WHERE
column1= TO_DATE('!'
|| v_date
|| q'!','yyyy-mm-dd')!';
END;
This is the code I am currently trying to use
CREATE OR REPLACE PROCEDURE my_procedure(
p_column1 IN VARCHAR2
,p_column2 IN VARCHAR2
)AS
v_query VARCHAR2(5000);
v_column1 VARCHAR2(10);
v_column2 VARCHAR2(10);
v_column1 := p_column1;
v_column2 := p_column2;
v_query := q'!
SELECT column1
FROM mytable
where
column1 BETWEEN TO_DATE('!' ||v_date || q'!,'yyyy-mm-dd')
AND TO_DATE( '!' ||v_end_date || q'!,'yyyy-mm-dd')!';
END;
How can I delimit the between to_date to be one column?
You've lost the closing quote after the v_date and v_end_date values:
where
column1 BETWEEN TO_DATE('!' ||v_date || q'!','yyyy-mm-dd')
--------------------------------------------^
AND TO_DATE( '!' ||v_end_date || q'!','yyyy-mm-dd')!';
--------------------------------------------^
You can debug problems like this by doing:
dbms_output.put_line(v_query);
With a random date value that shows your original query as:
SELECT column1
FROM
mytable
where
column1= TO_DATE('2011-12-13','yyyy-mm-dd')
and your modified one as:
SELECT column1
FROM
mytable
where
column1 BETWEEN TO_DATE('2011-12-13,'yyyy-mm-dd')
AND TO_DATE( '2012-01-02,'yyyy-mm-dd')
which makes the missing quotes in both to_date() calls more obvious than they are during construction. (And trying to execute that gets ORA-00907: missing right parenthesis.)
With my modification that now comes out as:
SELECT column1
FROM
mytable
where
column1 BETWEEN TO_DATE('2011-12-13','yyyy-mm-dd')
AND TO_DATE( '2012-01-02','yyyy-mm-dd')
which looks more reasonable.
Hopefully those v_* variables are strings. If they are dates then you should not be relying on NLS sessions to convert them to dates. Either way you should probably be using bind variablesm then supplying the actual values when you execute the dynamic query - though it isn't obvious why this is dynamic, so perhaps that constructed query is being passed back for something else to run.

Identify and retrieve values of all varchar columns in a Oracle database

I have the following query that gives me a result set of all tables and columns in my Oracle database of VARCHAR columns:
SELECT ATC.OWNER, ATC.TABLE_NAME, ATC.COLUMN_NAME
FROM all_tab_columns ATC
WHERE DATA_TYPE LIKE '%VARCHAR%'
To this I want to add a 4th column that displays the value of ATC.COLUMN_NAME. Is there an easy way of doing this?
I thought of doing a join to a SQL statement that loops through ATC.COLUMN_NAME and outputting the value. The join would be done on the table name.
I don't know if I'm complicating it and I can't think of the SQL. I've tried declaring the above statement in a variable and then using a CTE to interrogate it but I would still need to loop through the table_name and column_name values.
Is there a simpler way?
Edit: Sample data
You need to use dynamic SQL. this is a proof of concept, it will not scale well when run against a large database.
declare
stmt varchar2(32767);
val varchar2(4000);
rc sys_refcursor;
begin
for r in ( SELECT ATC.OWNER, ATC.TABLE_NAME, ATC.COLUMN_NAME
FROM all_tab_columns ATC
WHERE DATA_TYPE LIKE '%VARCHAR%' )
loop
stmt := ' select distinct '|| r.column_name ||
' from '|| r.owner||'.'||r.table_name;
open rc for stmt;
loop
fetch rc in val;
exit when rc%notfound;
dbms_output.put_line ( r.owner||'.'||r.table_name ||'.'|| r.column_name
||': '|| val );
end loop;
end loop;
end;

Get list of columns and alias name by a query string in Oracle

I'm using Pl/SQL with Oracle Database 11g.
I want to get a list of columns with alias by a query string.
There is a way to get all the column names of a query, using dbms_sql.describe_columns2 but only I get alias.
For example:
DECLARE
l_cursor NUMBER := dbms_sql.open_cursor;
l_ignore NUMBER;
l_desc dbms_sql.desc_tab2;
l_cnt NUMBER;
BEGIN
dbms_sql.parse( l_cursor, 'select a.col1 column1, a.col2 column2 from table_test a', dbms_sql.native );
dbms_sql.describe_columns2( l_cursor, l_cnt, l_desc );
FOR i IN 1 .. l_cnt LOOP
dbms_output.put_line(l_desc(i).col_name);
END LOOP;
dbms_sql.close_cursor( l_cursor );
END;
/
Returns:
column1
column2
Is there any way to get the values a.col1, or a.col2 with alias in the query?
The column names used in a SQL statement can be retrieved using Rob van Wijk's custom view DBA_DEPENDENCY_COLUMNS.
Install the view as SYS and grant select on dba_dependency_columns to <your user>;.
The view only works on objects. Create a VIEW on the SELECT statement and then the dependencies will be available. For example:
create table table_test(col1 number, col2 number);
create or replace view test_view as
select a.col1 column1, a.col2 column2 from table_test a;
select referenced_column
from sys.dba_dependency_columns
where owner = user
and name = 'TEST_VIEW'
order by 1;
Results:
REFERENCED_COLUMN
-----------------
COL1
COL2
The above results get the "list of columns". But part of your answer also implies you may want to get the "column expressions". That would be a completely different task, but is possible. Parsing SQL can be ridiculously difficult so it might help to explain exactly what you want and why you want it.

Resources