Bind variables in SELECT statement - oracle

I have tables in my Oracle database
PROJECTINFO
NAME SCHEMA
--------------------------
Test W_TEST_000
SAMPLESET
NAME SS_ID
--------------------------
Test_SSet 1049
in my SQL*Plus script a have a substitution variable (set directly or from user input)
DEFINE Project_Name = 'Test'
DEFINE SampleSet_Name = 'Test_SSet'
Now I need another two bind variables
VAR Project_Schema varchar2(50)
VAR SampleSet_ID number
Then I need to place a result of a SELECT statement into two bind vars
SELECT SCHEMA INTO :Project_Schema FROM PROJECTINFO WHERE NAME = '&Project_Name';
SELECT SS_ID INTO :SampleSet_ID from SAMPLESET WHERE NAME = '&SampleSet_Name';
Now I need to use both :Project_Schema and :SampleSet_ID in SELECT statement from W_TEST_000.MY_TABLE subtable like this:
SELECT NAME FROM :Project_Schema.MY_TABLE WHERE SS_ID = :SampleSet_ID
But this does not work.. (ORA-00903: invalid table name)
How to use bind variables in future SQL requests within the same SQL*Plus script?

it will work if you encapsulate the selects in PL/SQL blocks e.g.
DEFINE Project_Name = 'Test'
DEFINE SampleSet_Name = 'Test_SSet'
VAR Project_Schema varchar2(50)
VAR SampleSet_ID number
begin
SELECT SCHEMA
INTO :Project_Schema
FROM PROJECTINFO
WHERE NAME = '&Project_Name';
end;
/
begin
SELECT SS_ID
INTO :SampleSet_ID
from SAMPLESET
WHERE NAME = '&SampleSet_Name';
end;
/
--test the contents of the variable
Select :SampleSet_ID, :Project_Schema from dual;

Related

How to define a parameter that will be used as an IN argument inside a function?

I want to make a function that receives two parameters. The first one represents the salaries from a group of employees, and second one, the codes from a group of departments. Both, P_IN_SALARIES and P_IN_DEPARTMENTS_CODES parameters, will be used as
arguments in an IN function of a query, just as demonstrated in the code below:
CREATE OR REPLACE FUNCTION public.get_employees_id(P_IN_SALARIES WHICH_TYPE_COMES_HERE, P_IN_DEPARTMENTS_CODES WHICH_TYPE_COMES_HERE)
RETURNS text
LANGUAGE plpgsql
AS $function$
declare
v_employees_ids text;
begin
select STRING_AGG(employee.id || '', ',') into v_employees_ids
from employee
inner join departament on department.id = employee.departament_id
where employee.salary in (P_IN_SALARIES)
and department.code in (P_IN_DEPARTMENTS_CODES);
RETURN v_employees_ids;
END;
$function$
What is the type of a IN parameter in a SQL statement?
Is there a generic one that I might use in order to allow a kind of portability on an occasional database exchange (e.g. to Oracle)?
How to call this function in a hibernate query?
In Oracle, you can use a collection data type:
CREATE TABLE number_list IS TABLE OF NUMBER;
Then you can use the MEMBER OF operator rather than IN:
CREATE FUNCTION public.get_employees_id(
P_IN_SALARIES IN number_list,
P_IN_DEPARTMENTS_CODES IN number_list
) RETURNS VARCHAR2
IS
v_employees_ids VARCHAR2(4000);
BEGIN
SELECT LISTAGG( id, ',' ) WITHIN GROUP ( ORDER BY id )
INTO v_employees_ids
FROM employee e
inner join departament d
on ( d.id = e.departament_id )
WHERE e.salary MEMBER OF P_IN_SALARIES
AND d.department.code MEMBER OF P_IN_DEPARTMENTS_CODES;
RETURN v_employees_ids;
END;
/

Write an Oracle procedure

I must create an oracle procedure to display a list of persons (parlimentaries) with an index for tuples.
For now, I wrote this piece of code (I haven't implemented the index)
create or replace procedure parlamentarieslist as
begin
select
ssn,
name,
surname,
from
parlimentaries p,
mandate m
where
p.ssn = m.parlamentaries AND m.legislature= (select
max(legislature) "m"
from mandate);
end parlamentarieslist;
However, oracle give me these errors
Error(5,3): PL/SQL: SQL Statement ignored
Error(12,3): PL/SQL: ORA-00936: missing expression
Why?
As I mentioned before in the comment part, the problem is due to
the missing INTO clause
existing typo(comma) after surname column in the uppermost select list.
Mostly, Procedures are used to return one column or single row and in results of SELECT statements may be returned to the output parameters by INTO clause. But, If you want to return list of persons (multi-rows), the following style may be more suitable :
SQL> set serveroutput on;
SQL> create or replace procedure parlamentarieslist as
begin
for c in
(
select p.ssn, p.name, p.surname,
max(m.legislature) over (partition by p.ssn ) m
from parlimentaries p inner join mandate m
on ( p.ssn = m.parlamentaries )
order by m.legislature desc
)
loop
dbms_output.put_line(' SSN : '||c.ssn||' Name : '||c.name||' Surname : '||c.surname);
end loop;
end parlamentarieslist;
/
SQL> exec parlamentarieslist;
Where Use a SQL of explict ANSI JOIN style, instead of old-fashioned comma seperated JOIN style.

Oracle data modeler: How Create prodcedure and function

How create procedure e.g.:
Create PROCEDURE il_klub as (
select
sum(krk.kluby_id),
r.nazwa
FROM
rozgrywki_klubowe r,
kluby_roz_klub krk
WHERE
r.id = krk.rozgrywki_klubowe_id
GROUP by r.nazwa
)
and function e.g.:
DECLARE #mistrz TABLE (nazwa varchar, rozgrywki varchar)
INSER INTO #mistrz (nazwa, rozgrywki)
select
k.nazwa, r.nazwa
from
kluby k,
rozgrywki_klubowe r,
kluby_roz_klub krk,
historia_roz_klub hrk,
where
k.id = krk.kluby_id and k.id = hrk.kluby_id and r.id = krk.rozgrywki_klubowe_id
and r.id = hrk.rozgrywki_klubowe_id
and hrk.miejsce =1 and r.system like 'ligowy'
Select * from #mistrz
In Oracle SQL Data Modeler
The syntax for a procedure declaration is
CREATE OR REPLACE PROCEDURE IL_KLUB AS
vSUM_KLUBY KLUBY_ROZ_KLUB%TYPE;
vNAZWA ROZGRYWKI_KNUBOWE.NAZWA%TYPE;
BEGIN
select sum(krk.kluby_id),
r.nazwa
INTO vSUM_KLUBY,
vNAZWA
FROM rozgrywki_klubowe r,
kluby_roz_klub krk
WHERE r.id = krk.rozgrywki_klubowe_id
GROUP by r.nazwa;
END IL_KLUB;
This procedure is, obviously, not particularly useful as it doesn't do anything with the results of the SELECT, and that will probably draw a compilation warning. But that's how you declare it.
A function is defined in similar fashion, but you also need to define a return type, and then return a value:
CREATE OR REPLACE FUNCTION IL_KLUB_NAZWA
RETURN ROZGRYWKI_KNUBOWE.NAZWA%TYPE
AS
vSUM_KLUBY KLUBY_ROZ_KLUB%TYPE;
vNAZWA ROZGRYWKI_KNUBOWE.NAZWA%TYPE;
BEGIN
select sum(krk.kluby_id),
r.nazwa
INTO vSUM_KLUBY,
vNAZWA
FROM rozgrywki_klubowe r,
kluby_roz_klub krk
WHERE r.id = krk.rozgrywki_klubowe_id
GROUP by r.nazwa;
RETURN vNAZWA;
END IL_KLUB_NAZWA;
Oracle PL/SQL Language Reference here
Oracle SQL Language Reference here
Best of luck.

Record type reflection / populating a record variable of an unknown type (PL/SQL)

I have a package with a record type and a variable of that type in it:
CREATE PACKAGE my_package AS
TYPE t_rec IS RECORD(
id NUMBER,
name VARCHAR2(100),
last_updated DATE
);
v_var t_rec;
END;
I want to create an universal procedure for populating any record variable, so it can be called like this:
BEGIN
populate_record('my_package.v_var', 'MY_TABLE', CHARTOROWID(:VAR1));
END;
The logic of that procedure may look like this:
PROCEDURE populate_record(
p_var_name IN VARCHAR2,
p_table_name IN VARCHAR2,
p_rowid IN ROWID
) IS
BEGIN
-- determining a type of a given record variable
-- determining names and data types of given record variable's columns
-- selecting a row from a given table by a given rowid
-- filling out a given record variable by mapping table columns
-- to record columns by their names (using dynamic PL/SQL)
END;
But I have no idea how to obtain information about a given record. Are there any data dictionary views or built-in functions for querying record type columns?
Thanks.
P.S.: 11.2
UPDATED
I found a way to obtain info about records using PL/Scope:
CREATE OR REPLACE VIEW user_record_types AS
SELECT
i.object_name package_name,
i.name type_name
FROM
user_identifiers i
WHERE
i.object_type = 'PACKAGE'
AND i.type = 'RECORD'
AND i.usage = 'DECLARATION'
/
CREATE OR REPLACE VIEW user_record_types_columns AS
SELECT
i1.object_name package_name,
i1.name type_name,
ROW_NUMBER() OVER (
PARTITION BY
i1.object_name,
i1.name
ORDER BY
i2.usage_id
) column_num,
i2.name column_name,
i3.name column_type,
i3.type column_type_class
FROM
user_identifiers i1,
user_identifiers i2,
user_identifiers i3
WHERE
i1.object_type = 'PACKAGE'
AND i1.type = 'RECORD'
AND i1.usage = 'DECLARATION'
AND i2.object_name = i1.object_name
AND i2.object_type = i1.object_type
AND i2.type = 'VARIABLE'
AND i2.usage = 'DECLARATION'
AND i2.usage_context_id = i1.usage_id
AND i3.object_name = i2.object_name
AND i3.object_type = i2.object_type
AND i3.usage = 'REFERENCE'
AND i3.usage_context_id = i2.usage_id
/
CREATE OR REPLACE VIEW user_record_variables AS
SELECT
i1.object_name package_name,
i1.name variable_name,
CASE i2.type
WHEN 'RECORD' THEN
i2.object_name
WHEN 'PACKAGE' THEN
i2.name
END type_package_name,
CASE i2.type
WHEN 'RECORD' THEN
i2.name
WHEN 'PACKAGE' THEN
i3.name
END type_name
FROM
user_identifiers i1,
user_identifiers i2,
user_identifiers i3
WHERE
i1.object_type = 'PACKAGE'
AND i1.type = 'VARIABLE'
AND i1.usage = 'DECLARATION'
AND i2.object_name = i1.object_name
AND i2.object_type = i1.object_type
AND i2.type IN ('RECORD', 'PACKAGE')
AND i2.usage = 'REFERENCE'
AND i2.usage_context_id = i1.usage_id
AND i3.object_name (+) = i2.object_name
AND i3.object_type (+) = i2.object_type
AND i3.type (+) = 'RECORD'
AND i3.usage (+) = 'REFERENCE'
AND i3.usage_context_id (+) = i2.usage_id
/
But there is a problem when I use %ROWTYPEs, because there is no info about "what of" that %ROWTYPE is. So I think that PL/Scope is not a complete solution...
You can try to use table user_identifiers or all_identifiers if you have the access, as this other SO post shows.
You may need to recompile your packages:
alter package my_types compile plscope_settings='IDENTIFIERS:ALL' reuse settings;
Unfortunately this is only available from 11gR1.

Query Oracle for running sql and value of bind variables

If I run the SQL in Fig. 1 below, it may return something like this:
Select fname, lname from name_tbl where nam_key = :key
Without using some fancy DBA trace utility, how can I query an Oracle system table to find the value of the bind variable “:key”?
Figure 1. - List the current running sql statement.
select sid, username, sql_text
from v$session,
v$sqltext
where sql_address = address
and sql_hash_value = hash_value
order by sid, piece;
select name, value_string
from v$sql_bind_capture
where sql_id = your_query_id
Upd. or, of course:
select sql_id, value_string
from v$sql_bind_capture
where name = ':key'

Resources