PL-SQL bind variables in TCL - plsql

Could some one explain in the following TCL source code:
set sql "SELECT PROD.KEY || ' {' || PARAMETERS || '}' \
FROM PRV_PROD_MAPPING PROD \
WHERE PROD.SERVICE_ID = :service_id \
AND (PROD.KEY || ' ' || PROD.KEY_VAL) \
IN (:keys) "
what :service_id and :keys mean. Could I see the values behind by simple trace.
How could I find where these vars are defined?
Thanks in advance!

It's not TCL its an SQL query embedded in a TCL string, specifically one that binds a variable, which is then assigned to a normal TCL variable
As glenn points out, on its own this snippet of TCL does very little. presuembly somewhere in your program you actually connect to a DB and pass it a query from this string and some other variables

If you're using TDBC, you might have
# assume the connection has already occured and is named "db"
set sql "SELECT ... WHERE a.b=:service_id IN (:keys)"
set statement [db prepare $sql]
# get the bind variables' values from the local context:
set service_id 42
set keys [join {key1 key2 key3} ,]
set resultset [$statement execute]
# or, without setting the "service_id" and "keys" variables,
# provide them as an argument to the execute subcommand
unset service_id keys
set resultset [$statement execute {service_id 24 keys "foo,bar,baz"}]

As others pointed out it you just assign a string* to a variable.
More exactly, you assign the following string to a variable called sql
SELECT PROD.KEY || ' {' || PARAMETERS || '}' FROM PRV_PROD_MAPPING PROD WHERE PROD.SERVICE_ID = :service_id AND (PROD.KEY || ' ' || PROD.KEY_VAL) IN (:keys)
The values of :service_id and :keys are bound values that are passed later (In a oraplexec statement probably).
|| is string concatenation in SQL. So PROD.KEY || ' {' || PARAMETERS || '}' could be PRODKEY {PARAMETERS}.
*Everything is a string

I've done it using traces:
sys.DBMS_SYSTEM.SET_EV(n_sid, n_serial, 10046, 12, '');
DBMS_OUTPUT.put_line('Trace started: ' || to_char(SYSDATE,'dd.mm.yyyy hh24:mi:ss'));

Related

Python 2.7 sqlite3 how to determine empty field

I'm accessing an sqlite3 with a Python script, using
input_data = None
connection = sqlite3.connect(db_path)
db = connection.cursor()
read_string = 'select viewer_id, email, device_group, created_date, path_found, analyzed from ' + db_table + ' where analyzed < ' + str(cfg_history_number_of_days) + ';'
db.execute(read_string)
input_data = db.fetchall()
connection.close()
and this works great when there's data in the 'analyze' field. When 'analyze' s empty, the script considers the field to have a value much greater than my string value, and this test fails. How can I change my script so that I can determine whether the field is blank in the database?
Any comparison with NULL fails. To make NULL values behave as if they were a small string, replace them with a small string:
SELECT ... FROM db_table WHERE ifnull(analyzed, '') < ...;

Escaping percent signs in Lua Sqlite3 Prepare Statement

I have a statement:
(db is a sqlite3 instance)
local stmt = db:prepare("SELECT id, name FROM table WHERE name LIKE '%?%'")
if stmt:bind_values("test") == sqlite3.OK then
....
end
However, I get this error:
Incorrect number of parameters to bind (1 given, 0 to bind)
It seems it is not seeing the ? as a parameter. I have tried all kinds of escaping from %% for the percent signs to \ and \\ and beyond...driving me crazy.
Anyone know how to fix this? Thank you!
You can't put parameters inside quotes:
correct: SELECT ... WHERE foo = ?
incorrect: SELECT ... WHERE foo = '?'
With the quotes, it's just a string that contains a question mark. Without the quotes, it's a placeholder.
You'll have to build up the LIKE in pieces, e.g.
... WHERE foo LIKE '%' || ? || '%'

ORA-00904: invalid identifier during merge PLSQL

I am trying to run merge statement in following manner in PLSQL block and getting ORA-00904 error described below:
--Merge statement
l_mergestr1:='merge into pi_customer picu using (select * from table(picu_var)) src ' ||
' on (picu.customer_id = src.customer_id) when matched then update set '||l_newmergeupstr1||
' where picu.time_stamp <> pctemp.time_stamp when not matched then' ||
' insert ('||l_newmergeinsstr1||') values ('||l_newmergeinstvalstr1||')';
execute immediate l_mergestr1;
ORA-00904: "PICU_VAR": invalid identifier
Here picu_var is a variable of object_type which I have already declared.
Using dbms_output I verified the merge statement converts to following which I think is a correct syntax for merge and it works :
merge into pi_customer picu using (select * from table(picu_var)) src
on (picu.customer_id = src.customer_id) when matched then update set picu.Customer_Name=src.Customer_Name,picu.Server_Name=src.Server_Name,picu.Time_stamp=src.Time_stamp
where picu.time_stamp <> src.time_stamp when not matched then
insert (picu.Customer_ID,picu.Customer_Name,picu.Server_Name,picu.Time_stamp) values (src.Customer_ID,src.Customer_Name,src.Server_Name,src.Time_stamp)
I also verified there is no mismatch across source and target table column names and the merge syntax works when executed as what returned from dbms_output.
Please suggest how to avoid the error ORA-00904.
Does the syntax for merge declared in "l_mergestr1" requires a change?
You can't reference a variable from outside the dynamic SQL inside the dynamic SQL. Use a bind variable to pass it in:
l_mergestr1:='merge into pi_customer picu using (select * from table(:picu_bv)) src ' ||
' on (picu.customer_id = src.customer_id) when matched then update set '||l_newmergeupstr1||
' where picu.time_stamp <> pctemp.time_stamp when not matched then' ||
' insert ('||l_newmergeinsstr1||') values ('||l_newmergeinstvalstr1||')';
execute immediate l_mergestr1 using picu_var;

Trigger is not working properly?

Hello I exported database using datapump another schema so this synonyms must be in another new schema.
My old one is KTECH and new one is LTECH
DECLARE
strSynonyms_KTECH VARCHAR2(3000) := 'KTECH ';
strSynonyms_LTECH VARCHAR2(3000) := 'LTECH';
strCommand VARCHAR2(33865);
BEGIN
LOOP
FOR Synonym IN (SELECT * FROM ALL_SYNONYMS WHERE OWNER = strSynonyms_KTECH)
strCommand := 'CREATE OR REPLACE SYNONYM ' ||
Synonym.KTECH || '.' || Synonym.SYNONYM_NAME ||
' FOR ' || strSynonyms_LTECH || '.' ||
Synonym.TABLE_NAME;
EXECUTE IMMEDIATE strCommand;
END LOOP;
END;
I tried to run it but it shows me error.
you can export database synonyms from old schema as text file by using pl/sql or TOAD, then save the exported file as script, edit it then execute it on new schema.
by plsql developer:
by Toad:

Assign value to a field of rowtype where `field name` is a string

I want to assign a value to a rowtype's field but I don't know how to do it.
Suppose that I have a table X inside my database.
Suppose also that I have the following variables
a ( X%ROWTYPE ), representing a row of the table X
b ( VARCHAR2 ), containing a column name of the table X
c ( VARCHAR2 ), containing what I want to store inside a.b
What I want to do : something like a.b := c.
I've come up with something like this :
EXECUTE IMMEDIATE 'SELECT '|| c || ' INTO a.' || b || ' FROM DUAL';
Apparently, this isn't the right way to go. I get a ORA-0095: missing keyword error.
Can anyone help me with this ?
Here is the complete code :
DECLARE
tRow MyTable%ROWTYPE;
col_name VARCHAR(10) := 'Length';
nValue NUMBER(12,4) := 0.001;
dynamic_request VARCHAR(300);
BEGIN
dynamic_request := 'SELECT '|| nValue || ' INTO tRow.' || col_name || ' FROM DUAL';
EXECUTE IMMEDIATE dynamic_request;
END;
Ok, I solved it !
Short answer : Using a global variable does the trick
Answer Development
Let us consider two facts about dynamic PL/SQL blocks (i.e., PL/SQL blocks written as strings, to be executed trough an EXECUTE IMMEDIATE statement)
[1] There is no such thing as variable scope when you create a dynamic PLSQL block. What I mean by that is, if you do something like this :
CREATE OR REPLACE PROCEDURE DynamicVariableAssignment(
theString IN VARCHAR2
)
IS
BEGIN
EXECUTE IMMEDIATE 'BEGIN theString := ''test''; END; ';
END;
it will simply not work because the scope of theString is not transfered to the dynamic PL/SQL block. In other words, the dynamic PL/SQL block doesn't "inherit" of any variable, wherever it is executed.
[2] You might say "OK, no panic, I can give input/output arguments to my dynamic PL/SQL block, right ?". Sure you can, but guess what : you can only give SQL types as in/out ! True PL/SQL types on the other hand, such as a myTable%rowtype, are not accepted as an input for a dynamic PL/SQL block. So the answer of hmmftg won't work either :
-- I've reduced the code to the interesting part
dynamic_request := 'BEGIN :t_row.' || col_name || ':= 0.001; END;';
EXECUTE IMMEDIATE dynamic_request USING IN OUT tRow;
-- (where tRow is of type myTable%ROWTYPE)
since tRow is of MyTable%ROWTYPE, it is not a valid SQL type and is therefore not valid as an input to the dynamic PL/SQL block.
The Solution Who would have thought that global variables would come and save the day ? As we said in [1], we have no reference to any variable outside the dynamic PL/SQL block. BUT we can still access global variables defined in package headers !
Let us assume that I have a package kingPackage in which I define the following :
tempVariable myTable%ROWTYPE;
Then I can do this :
FINAL CODE (body only)
-- Copy tRow into temp variable
kingPackage.tempVariable := tRow;
-- We modify the column of the temp variable
vString := 'BEGIN kingPackage.tempVariable.' || col_val || ' := ' || TO_CHAR(vNumber) ||'; END;';
EXECUTE IMMEDIATE vString;
-- The column value has been updated \o/
tRow := kingPackage.tempVariable;
There you go, fellas !
Have a nice day
try this:
CREATE OR REPLACE PROCEDURE ROW_CHANGER(
tRow IN MyTable%ROWTYPE,
col_name IN VARCHAR,
nValue IN NUMBER)
AS
dynamic_request VARCHAR(300);
BEGIN
dynamic_request := 'BEGIN :t_row.'||COL_NAME ||':= :n_value; END;';
EXECUTE IMMEDIATE dynamic_request
USING IN OUT TROW, IN nValue;
END;
this is because in your EXECUTE IMMEDIATE the tRow MyTable%ROWTYPE is not defined,
so we defined it with using statement.

Resources