How bind variable is different from simple variable in plsql? what are their application? - sql

variable deptno number ;
deptno1 number;

Not sure what was your question really... However, I hope, The following answer/ post (from Alex Poole) should give you a fair idea how to define a variable in SQL /PL-SQL and how.
Declare bind variables in SQL*Plus
We try to 'bind' them in both ways and avoid literals.

A bind variable is part of the interface between SQL and the calling application or host language, so if your 'simple variable in PL/SQL' is not used in a SQL statement then it isn't a bind variable :)
declare
msg varchar2(100) := 'Hello';
begin
dbms_output.put_line(msg);
end;
In the case of actual bind variables, these are identical whatever way you do it. The PL/SQL compiler just builds the code for you behind the scenes.
Plain PL/SQL:
declare
l_dummy varchar2(1) := 'X';
l_result integer;
begin
select count(*) into l_result from dual where dummy = l_dummy;
dbms_output.put_line(l_result);
end;
Bind variable explicitly defined in SQL*Plus:
var dummy varchar2(1)
exec :dummy := 'X'
declare
l_result integer;
begin
select count(*) into l_result from dual where dummy = :dummy;
dbms_output.put_line(l_result);
end;
Either way you will see from v$sql, dbms_xplan etc that the SQL it actually executed was
SELECT COUNT(*) FROM DUAL WHERE DUMMY = :B1

The main difference is performance-wise. Bind variables can be used to parse a query once and save future parses every time you run the query with different values.
Using regular variables forces Oracle to do a hard parse every time the value of the variables change.

Related

Assign value to value of a variable in SQL

I have a variable called LV_MAIN which is having value as LV_TEMP and now I want to assign value to LV_TEMP and write select for LV_TEMP. How can I achieve this?
To explain in detail:
LV_MAIN := LV_TEMP
and now I want to assign:
LV_TEMP := '7'
and want to execute:
SELECT :LV_TEMP FROM DUMMY;
How can I do that?
To execute SQL Script, a "logic container" is required.
This "logic container" can be a trigger, a stored procedure, a table function, or an anonymous block.
For simple once-off queries or prototyping, the anonymous block is the option most readily usable:
DO BEGIN -- this indicates the start of the anon. block
DECLARE lv_temp NVARCHAR(2) := '7';
SELECT
:lv_temp
FROM
DUMMY;
END; -- this indicates the end of the anon. block

PL/SQL equivalent of SELECT statement

What would be the PL/SQL equivalent of this SQL query:
SELECT * FROM table(OWNER.PACKAGE.get_exam('123456789'));
This is the Function that I am trying to call:
FUNCTION get_exam(id IN VARCHAR2)
RETURN ab_assign_v1
IS
CURSOR c_exams(cid VARCHAR2) IS
SELECT t_api_exam_v1(
sei.person_id, --unique id
l.description --loc description
)
FROM my_view sei
JOIN loc l
ON sei.loc_code = l.loc_code
v_collection ab_assign_v1;
BEGIN
OPEN c_exams(id);
FETCH c_exams BULK COLLECT INTO v_collection;
CLOSE c_exams;
RETURN v_collection;
EXCEPTION
WHEN OTHERS THEN
error_a1.raise_error(SQLCODE, SQLERRM);
END get_exam;
Hope this helps.
DECLARE
lv <COLLECTION_NAME>;
BEGIN
lv:= OWNER.PACKAGE.get_exam('123456789');
dbms_output.put_line(lv.COUNT);
END;
/
Assuming that you want to return the result of a function :
select owner.package.get_exam('123456789') from table
Your function returns a nested table type. You simply need to declare a variable of that type, and assign to it as you would if it were a scalar:
declare
l_coll your_collection_type;
begin
l_coll := OWNER.PACKAGE.get_exam('123456789');
end;
/
In this example your_collection_type is a placeholder for whatever object your function actually returns.
" I am getting this error: PLS-00201: identifier 'ab_assign_v1' must be declared "
ab_assign_v1 is the type used by your function. From the code posted in your revised question it seems that type is in the same schema which owns the package with the function. However your original pseudo-code prefixes the call with the schema name. So, putting two and two together, you need to revise the variable declaration to include the schema too. (You may need to grant EXECUTE on it too, if you haven't done this already).
declare
l_coll OWNER.ab_assign_v1;
begin
l_coll := OWNER.PACKAGE.get_exam('123456789');
end;
/

Test if anything was updated in dynamic query

I need to construct and execute an UPDATE statement dynamically. Then I need to test whether anything was updated at all. My code is as follows:
DECLARE
v_table_name text;
v_column_name text;
v_debug_flag boolean;
v_upd_stmt text;
BEGIN
select nm_table_name, replace(nm_table_name, 'CDB_', 'ID_')
into strict v_table_name, v_column_name
from m_entity e
where id=12;
v_upd_stmt := format('update %s set id_lock_usr =null, dt_lock=null where %s=$1 returning id_lock_usr',
v_table_name,
v_column_name);
execute v_upd_stmt using p_id;
END
How to know if anything was updated?
How to know if anything was updated ?
Various options. In a plpgsql function, you can check the special variable FOUND to see if the last SQL command affected any rows.
IF FOUND THEN ...
However, For dynamic queries with EXECUTE use GET DIAGNOSTICS instead. The manual:
Note in particular that EXECUTE changes the output of GET DIAGNOSTICS,
but does not change FOUND.
Related:
Dynamic SQL (EXECUTE) as condition for IF statement
Aside:
I see lingering problems with properly escaped identifiers (especially with upper case table names like you have), possibly even SQL injection. Fix with:
DECLARE
v_table_name text;
v_column_name text;
v_id_lock_usr integer; -- guessing the data type
i integer;
BEGIN
SELECT nm_table_name, replace(nm_table_name, 'CDB_', 'ID_')
INTO strict v_table_name, v_column_name
FROM m_entity e
WHERE id = 12;
EXECUTE format('UPDATE %I SET id_lock_usr = null, dt_lock = null
WHERE %I = $1 RETURNING id_lock_usr'
, v_table_name,
, v_column_name)
INTO v_id_lock_usr; -- to store the *single* result from RETURNING
GET DIAGNOSTICS i = ROW_COUNT;
IF i > 0 THEN
-- do something
END IF;
END
Note %I instead of %s.
In your case, if id_lock_usr returned by your query is NOT NULL (reliably), you might just test the result directly instead:
IF v_id_lock_usr IS NOT NULL ...
And you might want to schema-qualify table names to avoid ambiguities. But you must escape schema_name.table_name as two separate identifiers ..
Related:
Are PostgreSQL column names case-sensitive?
Define table and column names as arguments in a plpgsql function?
Table name as a PostgreSQL function parameter

PL/SQL query with parameter

I am familiar with MSSQL and using a parameter within the query, but I am not sure how I would do this within PL/SQL.
DECLARE
LSITEID NUMBER := 100001;
BEGIN
SELECT * from invoicehead ih
JOIN sitemaster sm on sm.SITEIID = ih.SITEIID
JOIN invoiceline il on il.invoiceIID = ih.invoiceIID
WHERE
ih.StartDate BETWEEN '2015-12-01' AND '2016-03-07'
AND SITEIID IN ( LSITEID)
END;
Right now I am testing this within Pl/SQL. But essentially I would be passing in the query with the parameter from MSSQL Linked Server OPENQuery.
How I can run the above query in PL/SQL with the parameter?
There is plenty of other resource for finding an answer, e.g. here (Tutorialspoint) or specifically here (plsql-tutorial). But perhaps I have missed your point.
To not remain on merely citing links, your query could look like this:
DECLARE
LSITEID integer;
BEGIN
LSITEID := 100001;
-- dostuff
END;
Two things to note: First, in a declare part (as I have learnt it) you should avoid assigning values. Second, if you intend to pass in different parameters you could/should use a procedure.
In PL/SQL you just use the name of the argument. In the following example, the argument is P_VALUE, note select statement says where dummy = p_value.
DECLARE
FUNCTION dummycount (p_value IN DUAL.dummy%TYPE)
RETURN INTEGER
AS
l_ret INTEGER;
BEGIN
SELECT COUNT (*) c
INTO l_ret
FROM DUAL
WHERE dummy = p_value;
RETURN l_ret;
END dummycount;
BEGIN
DBMS_OUTPUT.put_line ('A: ' || dummycount (p_value => 'A'));
DBMS_OUTPUT.put_line ('X: ' || dummycount (p_value => 'X'));
END;
This results in the following output:
A: 0
X: 1

variable as column name in where clause in Oracle PL/SQL

I am working on PL/SQL code where I need to perform a select query using variable as column name in where clause. Column names are stored in a table as varchar and I am using a loop to pass those column names to my select statement.
Please find sample code segment I am trying to run:
set serveroutput on;
declare
var varchar2(100);
counter number;
begin
var:='description';
select count(*)
into counter
from nodetable
where var like '%Ship%';
dbms_output.put_line(counter);
end;
Output:
anonymous block completed
0
However the result should be 86.
Oracle is comparing last condition as two string and not column=string.
Please let me know if this is even feasible in oracle or if there is a workaround for it.
Regards
Ankit
You have to use dynamic SQL, preferrably with bind-variables:
EXECUTE IMMEDIATE
'select count(*) from nodetable where '||var||' like :p1'
INTO counter
USING '%Ship%';
Try this
declare
var varchar2(100);
counter number;
begin
var:='description';
EXECUTE IMMEDIATE
'select count(*)
into counter
from nodetable
where '||var||' like ''%Ship%'' ';
dbms_output.put_line(counter);
end;
You need to be carefull with the colon's (').
I agreed with previous answer in implementation, but i strictly recommend you to change your technical requirements, because you can't use bind variables for this, and it's potential place for injection. For example, if someone will edit value in your table which stores column names, to something like that: "description = inject_function or description". Then your dynamic sql block will execute this statement:
select count(*) from nodetable where description = inject_function or description like '%Ship%
and example implementation of function
create function inject_function
return varchar2
is pragma autonomous_transaction;
begin
delete * from most_important_table;
commit;
return to_char(null);
exception when others then
rollback;
return to_char(null);
end;