ADODB.Recordset addnew with an Oracle package field - oracle

Hy guys.
I have a visual basic 6 program with an Oracle DB. When i add a record to table i do:
Adodc1.Recordset.AddNew
Adodc1.Recordset.Fields("Title") = "Titolo"
Adodc1.Recordset.Fields("Author") = "Autore"
Adodc1.Recordset.Fields("IP") = "10.0.1.1"
Adodc1.Recordset.Update
This routine is ok, but i want to set IP with an oracle function: sys_context('USERENV','IP_ADDRESS')
When i have modified my routine in
Adodc1.Recordset.AddNew
Adodc1.Recordset.Fields("Title") = "Titolo"
Adodc1.Recordset.Fields("Author") = "Autore"
Adodc1.Recordset.Fields("IP") = "sys_context('USERENV','IP_ADDRESS')"
Adodc1.Recordset.Update
the field of table is always null.
There are workaround for this problem?
Thanks in advance

I think the simple answer is you cannot do it that way. As it is written you are assigning the fixed string 'sys_context('USERENV','IP_ADDRESS')' into the 'IP' field.
To use that function you will have to construct an INSERT statement and execute it directly. Somethink like
INSERT INTO your_table ( Title, Author, IP )
SELECT 'Titolo', 'Autore', sys_context('USERENV','IP_ADDRESS')
Alternatively you could create a stored procedure and execute that (which might be better in the long run)

Related

Oracle APEX 5 ITEM value

It's possible to get a Oracle APEX 5 item value inside SQL Developer ?
I know it'possible to use something like that:
SELECT *
FROM apex_050100.wwv_flow_data d
inner join apex_050100.wwv_flow_sessions$ s on d.flow_instance = s.id;
where d.flow_instance = <session_id_from_url>;
But i want to use the V function:
select v('ITEM') FROM DUAL;
Or event better to set this item value like this:
APEX_UTIL.SET_SESSION_STATE (
p_name IN VARCHAR2 DEFAULT NULL,
p_value IN VARCHAR2 DEFAULT NULL);
You should use bind variables instead of the v function. Rather than this:
select *
from table
where column = v('PX_ITEM_NAME');
Do this instead:
select *
from table
where column = :PX_ITEM_NAME;
This is safer (not vulnerable to SQL injection), more performant (avoids hard parses and uses shared cursors), and more convenient in that you can copy this over to SQL Developer.
When you run this in SQL Developer, you will be prompted for the values before the query is executed.

How to validate a query without executing in PowerBuilder

wondering if there is way to validate a query before executing
Is there way to check/validate Query without executing it?
One way that we validate SQL is to add a condition to the SQL that could never be true.
Example:
long ll_rc
long ll_result
string ls_sql, ls_test
string ls_message
//Arbitrary SQL
ls_sql = "SELECT * FROM DUAL"
//This SQL when executed will always return 0 if successful.
ls_test = "select count(*) from ( " + ls_sql + " WHERE 1 = 2 )"
DECLARE l_cursor DYNAMIC CURSOR FOR SQLSA ;
PREPARE SQLSA FROM :ls_test;
OPEN DYNAMIC l_cursor;
ll_rc = SQLCA.SQLCODE
choose case ll_rc
case 0
//Success
ls_message = "SQL is properly formed"
case 100
//Fetched row not found. This should not be the case since we only opened the cursor
ls_message = SQLCA.SQLERRTEXT
case -1
//Error; the statement failed. Use SQLErrText or SQLDBCode to obtain the detail.
ls_message = SQLCA.SQLERRTEXT
end choose
CLOSE l_cursor ; //This will fail if open cursor failed.
messagebox( "Result", ls_message )
Note: If your SQL is VERY complicated, which I suspect it isn't, the database optimizer may take several seconds to prepare your SQL. It will be significantly less time than if you run the entire query.
Since the database is the final arbitrator for what is "valid" (table and column names and such) the general answer is no. Now you could come up with a class in PB which checks statement syntax, object names, etc. so you wouldn't have to touch the db but it would be obsolete as soon as any changes were made to the db.
Put the select statement in any script and compile it. Part of the work will be to check the SQL syntax against the database you are connected to.
Watch out: you need at least one bound variable in the column list of your SQL statement. This is not the case for other DML statements.
Example:
in my case:
select noms into :ls_ttt from contacts;
results in a message Unknown columns 'noms' in 'field list'.
However,
select nom into :ls_ttt from contacts;
does not show any error.
Hope this helps.

How can I check a char in oracle sql from a select query?

I need to be able to check a different table's value before allowing input in separate table.
In oracle they don't allow subqueries in check so I am trying to make a function...
CREATE OR REPLACE FUNCTION chktrain(tid integer)
RETURN INTEGER
AS
chk1 char;
BEGIN
SELECT chk1 = (select train from trainer where trainer.trainer_id = tid);
IF chk1 = 'Y' THEN
return 1;
ELSE
return 0;
END IF;
END;
This won't work because I can't set chk1 to the subquery. Is there a way to do this?
I believe you are looking for the SELECT INTO statement.
I'm not entirely sure you need to use this function you are creating though, but I'm also not sure I fully understand what you are trying to do. Perhaps look into triggers, specifically BEFORE INSERT triggers, which could allow you to lookup a reference table and potentially translate a value every time you do an insert on a table.
You are looking for SELECT INTO statement like
SELECT train into chk1 from trainer
where trainer_id = tid;
You might find this documentation interesting and helpful.
You will find railroad diagrams for the syntax of if statements and usage details about the different forms of if statements.
https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/if_statement.htm
At the end of the page there is an example of the SELECT INTO statement.
(select train INTO chk1 from trainer where trainer.trainer_id = tid);

PL SQL - Stored procedure update column if parameter is not NULL

I've written a stored procedure that updates a table.
But I would like to take into account where one or more of the parameters are NULL.
In such an instance, I don't want to update the column, I want to leave the existing value as is.
I've tried to use:
UPDATE
VS_USER_T
SET
USR_FIRST_NAME = ISNULL(p_NewUsrFName, #p_NewUsrFName)
WHERE
USR_ID = lv_Num_UsrId;
But I get an error on the '#', I'm using Oracle 12c.
This is the procedure call
PROCEDURE UpdateUser
( p_UserId IN VS_USER_T.USR_ID%TYPE,
p_NewUsrFName IN VS_USER_T.USR_FIRST_NAME%TYPE,
p_NewUsrLName IN VS_USER_T.USR_LAST_NAME%TYPE,
p_NewUsrname IN VS_USER_T.USR_LOGIN%TYPE)
Please advise how my UPDATE statement should look like, when 'p_NewUsrname ' can be NULL, in which case I want to leave the existing value as is.
Thanks in advance.
To keep the existing value you need to refer to the existing column value:
USR_FIRST_NAME = ISNULL(p_NewUsrFName, USER_FIRST_NAME)
or you could use:
USR_FIRST_NAME = CASE WHEN p_NewUsrFName is null THEN USER_FIRST_NAME ELSE NewUsrFName END
ISNULL() is not yet a standard Oracle function (at least in the Oracle 12c version that you say you are using). If is of course possible to write a PL/SQL function called ISNULL() and use that.
For a standard Oracle 12c installation, try using NVL or COALESCE instead.
USR_FIRST_NAME = NVL(p_NewUsrFName, USR_FIRST_NAME)
or
USR_FIRST_NAME = COALESCE(p_NewUsrFName, USR_FIRST_NAME)
You could use a decode statement e.g.
update my_table t
set username = decode(p_NewUsrname, NULL, t.username, p_NewUsrname)
where t.id = p_UserId;

Parameter for IN query oracle [duplicate]

This question already has an answer here:
Oracle: Dynamic query with IN clause using cursor
(1 answer)
Closed 8 years ago.
SELECT * FROM EMPLOYEE
WHERE EMP_NAME IN (:EMP_NAME);
This is my query and now the EMP_NAME parameter I would like to send it as a list of strings.
When I run this query in SQL developer it is asked to send the EMP_NAME as a parameter, Now I want to send 'Kiran','Joshi' (Basically, I want to fetch the details of the employee with employee name either Kiran or Joshi. How should I pass the value during the execution of the query?
It works when I use the value Kiran alone, but when I concatenate with any other string it won't work. Any pointers in this?
I tried the one below
'Kiran','Joshi'
The above way doesn't work as understood this is a single parameter it tries the employee with the name as 'Kiran',Joshi' which won't come. Understandable, but in order to achieve this thing, how can I go ahead?
Any help would be really appreciated.
Thanks to the people who helped me in solving this problem.
I could get the solution using the way proposed, below is the approach
SELECT * FROM EMPLOYEE WHERE EMP_NAME IN (&EMP_NAME)
I have tried in this way and following are the scenarios which I have tested and they are working fine.
Scenario 1:
To fetch details of only "Kiran", then in this case the value of EMP_NAME when sql developer prompts is given as Kiran. It worked.
Scenario 2:
To fetch details of either "Kiran" or "Joshi", then the value of EMP_NAME is sent as
Kiran','Joshi
It worked in this case also.
Thanks Kedarnath for helping me in achieving the solution :)
IN clause would be implicitly converted into multiple OR conditions.. and the limit is 1000.. Also query with bind variable means, the execution plan will be reused.. Supporting bind variables for IN clause will hence affect the bind variable's basic usage, and hence oracle limits it at syntax level itself.
Only way is like name in (:1,:2) and bind the other values..
for this, you might dynamic SQL constructing the in clause bind variables in a loop.
Other way is, calling a procedure or function(pl/sql)
DECLARE
v_mystring VARCHAR(50);
v_my_ref_cursor sys_refcursor;
in_string varchar2='''Kiran'',''Joshi''';
id2 varchar2(10):='123'; --- if some other value you have to compare
myrecord tablename%rowtype;
BEGIN
v_mystring := 'SELECT a.*... from tablename a where name= :id2 and
id in('||in_string||')';
OPEN v_my_ref_cursor FOR v_mystring USING id2;
LOOP
FETCH v_my_ref_cursor INTO myrecord;
EXIT WHEN v_my_ref_cursor%NOTFOUND;
..
-- your processing
END LOOP;
CLOSE v_my_ref_cursor;
END;
IN clause supports maximum of 1000 items. You can always use a table to join instead. That table might be a Global Temporary Table(GTT) whose data is visible to thats particular session.
Still you can use a nested table also for it(like PL/SQL table)
TABLE() will convert a PL/Sql table as a SQL understandable table object(an object actually)
A simple example of it below.
CREATE TYPE pr AS OBJECT
(pr NUMBER);
/
CREATE TYPE prList AS TABLE OF pr;
/
declare
myPrList prList := prList ();
cursor lc is
select *
from (select a.*
from yourtable a
TABLE(CAST(myPrList as prList)) my_list
where
a.pr = my_list.pr
order by a.pr desc) ;
rec lc%ROWTYPE;
BEGIN
/*Populate the Nested Table, with whatever collection you have */
myPrList := prList ( pr(91),
pr(80));
/*
Sample code: for populating from your TABLE OF NUMBER type
FOR I IN 1..your_input_array.COUNT
LOOP
myPrList.EXTEND;
myPrList(I) := pr(your_input_array(I));
END LOOP;
*/
open lc;
loop
FETCH lc into rec;
exit when lc%NOTFOUND; -- Your Exit WHEN condition should be checked afte FETCH iyself!
dbms_output.put_line(rec.pr);
end loop;
close lc;
END;
/

Resources