Is there a way to use a bind parameter inside a lexical parameter query something like this?:
select col from tbl where col = :bind_param
note: the code above is an input in a lexical parameter
When saying a "lexical query", do you mean a "lexical parameter"?
If I understood you correctly, then yes - you can do that, by setting it in the After Parameter Form trigger. (BTW, that's where I set my lexical parameters' values, always).
Open Reports Online Help System and search for "lexical". It is very well described. I believe that this is what you are asking:
A lexical reference cannot be used to create additional bind variables
after the After Form trigger fires. For example, suppose you have a
query like the following (note that the WHERE clause is replaced by a
lexical reference):
SELECT ENAME, SAL FROM EMP
&where_clause
If the value of the where_clause parameter contains a reference to a
bind variable, you must specify the value in the After Form trigger or
earlier (*LF). You would get an error if you supplied the following value
for the parameter in the Before Report trigger:
WHERE SAL = :new_bind
If you supplied this same value in the After Form trigger, the report
would run.
(*LF) Now, that's somewhat contradictory - "or earlier" actually is the Before Report trigger, so ... take it with caution. As I've said (and I'll repeat it): I set lexical parameters' values in the After Parameter Form. Worked always (for me).
Related
i am trying to find out at what age an employee started working.
if he started under 16 he should report this 'Error when entering the date of birth' mistake. so my trigger is created but my trigger is not working
I get ever this error: ORA-01422: Exact retrieval returns more than the requested number of lines
i can't find the problem
Here is the code:
SET SERVEROUTPUT ON
ACCEPT Birthday PROMPT ' Pleas give you Date of birth: '
CREATE OR REPLACE TRIGGER T_Controll
before INSERT ON meine_Firma -- Table
FOR EACH ROW
DECLARE
V_Berufstart meine_Firma.Hiredate%TYPE; --Job begin
V_Geburtsdatum DATE; -- Date of birth
V_Alter number:=0; -- AGE
SELECT HIREDATE INTO V_Berufstart FROM meine_Firma;
BEGIN
V_Geburtsdatum:=('&Birthday');
V_Alter:= Round(MONTHS_BETWEEN(V_Berufstart,V_Geburtsdatum)-2)/12;
IF 16 > V_Alter THEN
RAISE_APPLICATION_ERROR(-20201,'Error when entering the date of birth');
END IF;
END;
/
SET SERVEROUTPUT OFF
If he under 16 then he may not work
sorry my english is not good (=
You have a much bigger issue in this script than the error you are getting. Even after correcting as #ShaunPeterson suggested it will still fail
, it WILL NOT generate an error it will just not run as you expect. The issue is you failed to understand substitution variables - the use of &name (Specifically here &Birthday.) I'll actually use &Birthday in the following but the discussion applies to ANY/ALL substitution variables.
people fail to understand why they can't use the "&" substitution
variables in their PL/SQL procedures and functions to prompt for input
at run time. This article will hopefully help clarify in your mind
what the differences are so that you can understand where and when to
use these.
Substitution Variables The clue here is in the name... "substitution". It relates to values being substituted into the code
before it is submitted to the database. These substitutions are
carried out by the interface being used
The effect of this substitution is the the line containing the substitution variable is physically rewritten by the interface replacing %Birthday. In this case if you don't enter a value or the date 2000-05-19 the statement before and after substitution is
BEFORE: V_Geburtsdatum:=('&Birthday');
AFTER: V_Geburtsdatum:=(''); OR V_Geburtsdatum:=('2000-05-19');
Either way the after is what the compiler sees; it does NOT see %Birthday at all. Moreover when run the trigger will not prompt for a value. As far as the compiler is concerned it is a hard coded value that will never change. Beyond that a trigger, or any other PLSQL script (stored or anonymous) never prompts for values, they are actually incapable of doing so as it is not part of the language. Any prompt is via your interface software not plsql.
I'm going to suggest a way to avoid the trigger altogether. Getting on soap box: Triggers are BAD, they have some usefulness for assigning auto incrementing keys (before 12c),logging, very limited auditing, etc. However, for business rules they should be the option of last resort. Ok Get off soap box.
The first thing is to make the columns meine_Firma.Hiredate and meine_Firma.Geburtsdatum NOT null (if not already). If either are NULL you cannot calculate anything with them, the result would be NULL.
Second create a new column age_at_hire (or whatever) as a virtual column then put a check constraint on it. And voila trigger no longer needed. See fiddle for demo.
So the proposed change (YES you will probably have to clean up the bad data first):
alter table meine_Firma modify
( hiredate not null
, Geburtsdatum not null
) ;
alter table meine_Firma add
( age_at_hire integer generated always as (trunc(months_between(hiredate,Geburtsdatum))) virtual
, constraint check_age_at_hire check (age_at_hire >= 16*12)
);
Anyway, I hope you get an understanding of substitution variables for the future. And learn to avoid triggers. Good luck.
The reason you are getting that specific error is that the below select will select ALL rows from meine_Firma as there is no where clause
SELECT HIREDATE INTO V_Berufstart FROM meine_Firma;
However because you are in a trigger you do not need to select anything you use the :NEW bind variable. So you can just use
V_Berufstart := :NEW.HIREDATE;
If this was an update trigger there would be both a :NEW and :OLD bind variable declared so that you can access the OLD and NEW values. As this is an Insert trigger the :OLD will just be null as there is no old values.
Does PeopleCode have something similar to reflection in C# whereby I can access a variable with the variable name stored in a string? I am aware of the # operator but I think it only applies to fields and records (correct me if I am wrong. I tried and couldn't get it to work.)
Basically, I need to access a Component variable by name with the name itself being variable.
You can do it by # :
Local string &sValue1 = "var1";
getting the value :
winmessage(#(&sValue1));
I read on internet and found that the IN parameter in procedure is pass by reference. Can you please explain this with an example? Thanks in advance.
To better understand, let's review how PL/SQL handles parameters in two ways:
By Reference
In this case, a pointer to the actual parameter is passed to the corresponding formal parameter. Both actual and formal parameters point to the same location in memory that holds the value of the parameter.
By Value
In this case, the value of the actual parameter is copied to the corresponding formal parameter. If the program then terminates without an exception, the formal parameter value is copied back to the actual parameter. If an error occurs, the changed values are not copied back to the actual parameter.
By default OUT and IN OUT parameters are passed by value and IN parameters are passed by reference. When an OUT or IN OUT parameter is modified inside the procedure the procedure actually only modifies a copy of the parameter value. Only when the procedure has finished without exception is the result value copied back to the formal parameter.
procedure add_numbers(
first_val in number,
second_val in out number
)
BEGIN
second_val := first_val + second_val;
--some other statements
END;
/
TEST:
BEGIN
par_in = 124;
par_inout = 76;
add_numbers(par_in, par_inout);
DBMS_OUTPUT.PUT_LINE(par_inout);
END;
/
The example above, will print 200 on the screen. There are two parameters passed to add_numbers procedure:
The first one is par_in which is of the mode IN. This parameter is passed by reference. Hence, in add_numbers procedure, no other copy of this parameter will be created. Rather, the same copy will be used. If you are allowed to modify the value first_val inside add_numbers procedure (but you are not), the value will reflect directly to par_in. Because simply both first_val and par_in are two names for the same memory location.
The second one is par_inout which is of the mode IN OUT. This parameter is passed by value by default. Hence, in add_numbers procedure, new (memory location) will be allocated to store the another copy of this parameter. Hence, par_inout is a name to different location in the memory than second_val. They two names to two different locations.
The implication of the second parameter is that, after the line second_val := first_val + second_val; is executed, the value of second_val is different to the value of par_inout until the end of the procedure. Only at the end of the procedure, the value of second_val will be passed to par_inout.
Now, if you pass a large collection as an OUT or an IN OUT parameter then it will be passed by value, in other words the entire collection will be copied to the formal parameter when entering the procedure and back again when exiting the procedure. If the collection is large this can lead to unnecessary CPU and memory consumption.
The NOCOPY Parameter Mode Hint alleviates this problem because you can use it to instruct the runtime engine to try to pass OUT or IN OUT parameters by reference instead of by value
The hint requests PL/SQL runtime engine to pass an IN OUT argument by reference rather than by value. This can speed up the performance of your programs, because by-reference arguments are not copied within the program unit. When you pass large, complex structures like collections, records, or objects, this copy step can be expensive.
I am trying to make a procedure return a subset of records as a single type a_ntt meeting a certain requirement for which I am trying to define a cursor a_cur, and this is the relevant code for my question:
a_t a_cur%ROWTYPE;
TYPE a_ntt IS TABLE OF a_t;
l_a a_ntt;
My database server throws PLS-00488 (invalid variable declaration object must be a type or subtype) considering variable a_t. I would like to know why. To me it seems I have provided a type to a_t, I would suggest ROWTYPE does that for me, but obviously I am not getting something.
I would like to know why this error occurs, why declaring a_t as a_cur%ROWTYPE does not prevent this.
Just to make sure, I have resolved the issue by adding %TYPE to the line, so TYPE a_ntt IS TABLE OF a_t%TYPE;, but I would like to know why this is necessary.
a_t is not a type. It is a variable whose type is a_cur%ROWTYPE. You can't use it as a type.
a_t%TYPE is a type though, so that works.
The syntax diagrams for the "collection variable declaration" is in the PL/SQL docs. You'll see that either you need a type, or a rowtype_attribute which has cursor, table or view name with %ROWTYPE attached, or a type_attribute which is essentially a variable name with %TYPE attached.
The worst aspect of the Interactive Report (IR) is that you cannot create it using a PL/SQL returning SQL statement. I have gotten around this using two methods:
1) APEX_COLLECTION.CREATE_COLLECTION in the Before Header Process, which takes a SQL statement (that is constructed in PL/SQL in the process), and have the IR's source be select c001 alias1, c002 alias2 ... from apex_collections a where collection_name = '...'
2) Make a badass pipeline function with a parameter list as long as you need and then have the IR's source be select * from table(package_name.pipelined_function_name(:P1_parameter1, :P1_Parameter2))
Is there a performance difference? I originally used the first method but then ran into an occurrence where it was giving me a bug so I tried the pipelined function and found I just liked it better and have tended to use them ever since unless it was inappropriate to do so (namely when there is a large number of items to be passed to the parameter).
First method gives you opportunity to cache data by re-creating the collection only when you need it. Using n00X and d00X columns will give you some additional performance and right column types for the report definition. You can also create a view based on that collection with type casting and column aliases to add more convenience:
create or replace view apx_my_report
as
select n001 id, c001 data, d001 some_date
from apex_collections
where collection_name = 'MY_REPORT'
/
In that case you report source will be like that:
select id, data, some_date from apx_my_report
/
On the other hand, when you need to execute an ad-hoc query every time when page is rendered, it leads to the unavoidable re-creation of a such collection, therefore the performance goes down because of unwanted transaction maintaining: undo, redo etc.
So, it depends.