i'm trying to call stored procedure on mybatis.
this is my code.
<insert id="insertWbs" parameterType="HashMap" useGeneratedKeys="true" keyProperty="wbs_unique">
<selectKey keyProperty="wbs_unique" resultType="string" order="BEFORE" statementType="CALLABLE">
<!-- <![CDATA[ SELECT #{proj_no}||WBS_${PROJ_NO}_SEQ.NEXTVAL FROM DUAL ]]> -->
<![CDATA[ CALL WBS_UNIQUE(#{proj_no, mode=IN, jdbcType=VARCHAR}, #{X, mode=OUT, jdbcType=VARCHAR}) ]]>
</selectKey>
insert into wbs(proj_no, task_name, wbs_worker, wbs_tester, wbs_ex_start, wbs_ex_end, wbs_unique, task_status)
select #{proj_no}, #{task_name}, #{wbs_worker}, #{wbs_tester}, to_date(#{wbs_ex_start}, 'yyyy-mm-dd'), to_date(#{wbs_ex_end}, 'yyyy-mm-dd'), #{wbs_unique}, #{task_status} from dual where not exists
(select wbs_unique from wbs where wbs_unique = #{wbs_unique})
</insert>
the first comment is what i tried to set dynamic sequence but it didn't worked.
this is the error
ORA-02289: sequence does not exist
so i decided to use stored procedure to set dynamic parameter which contains 'wbs_', '_seq'.
create or replace PROCEDURE WBS_UNIQUE
(
PROJ_NO IN VARCHAR2
,X OUT VARCHAR2
) AS
V_QUERY VARCHAR(1000);
BEGIN
V_QUERY := V_QUERY||'SELECT WBS_'||PROJ_NO||'_SEQ.NEXTVAL FROM DUAL';
EXECUTE IMMEDIATE V_QUERY into x;
END WBS_UNIQUE;
and it works fine on oracle 11g not mybatis...
the first code i attached throw this error
org.apache.ibatis.executor.ExecutorException: SelectKey returned no data.
i can't understand why it's not working on mybatis. did i do something wrong? probably i did but i don't know what i did wrong.
if anyone knows why this happens, please tell me.
thank you.
The first example looks good to me. This how I would do it myself:
<selectKey keyProperty="myId" resultType="java.lang.Integer" order="BEFORE">
SELECT ${proj_no}||WBS_${PROJ_NO}_SEQ.NEXTVAL FROM DUAL
</selectKey>
Do not use #{proj_no} but ${proj_no}. The former is for JDBC parameters; the latter (the one you need) is for SQL injection.
Alternatively, the problem could be the value of the property PROJ_NO (or is it proj_no?) leads to an invalid sequence name:
Can you check the value of this property?
Does that sequence actually exist? The error message says it doesn't.
By the way, shouldn't it look more "java-like", something like projNo?
Related
I'm trying to create a trigger in which, only under certain circumstances, an insert is performed on another table. Consider the following code:
create table journal (
pk integer primary key autoincrement,
dsc varchar(10) not null
);
create table users (
name varchar(30) primary key not null
);
create trigger users_ai
after insert on users
begin
select
case
when 1 then
insert into journal(dsc) values('foo')
end;
end;
I get the following error when I run this code:
Error: near line 10: near "insert": syntax error
In production, the "1" in the when clause would be replaced by a more complex expression. I've also tried "true" and get the same results. I've also tried surrounding the insert statement in parens and get the same results. Any ideas how to accomplish what I want?
If you look at the syntax diagram for "CREATE TRIGGER", you'll see your attempt just doesn't match. You can, however, simply use the WHEN branch (without needing FOR EACH ROW):
create trigger users_ai
after insert on users
when 1 begin
insert into journal(dsc) values('foo');
end;
OK, figured it out. Instead of putting a conditional expression in the block of the trigger, I used a when clause. Here's the code that works:
create trigger users_ai
after insert on users when 1
begin
insert into journal(dsc) values('foo');
end;
If that when expression is changed to something that returns false (say 0) then the insert isn't done. In production, the expression will sometimes return true, sometimes false, which, of course, is the point of this code. Thanks everybody!
I think that you want a CASE statement, not a CASE expression.
create trigger users_ai after insert on users
begin
case
when ... then insert into journal(dsc) values('foo');
when ... then ...;
else ...;
end case;
end;
Note: if your trigger needs access to the data that was just inserted, its definition should the for each row option.
You can try to use an INSERT ... SELECT and your expression in the WHERE clause.
...
INSERT INTO journal
(dsc)
SELECT 'foo'
WHERE 1 = 1;
...
1 = 1 needs to be replaced by your Boolean expression.
I don't know how to pass the custom table names (eg prepAccTN) so that the SP gets executed w/o ERROR 1146 (42S02): Table '[my-schema-name].prepacctn' doesn't exist
Tried executing it like so
CALL Bill_UpdateUnbalancedPrepaidAccounts('correct_table_name', 'boo', 3);
CALL Bill_UpdateUnbalancedPrepaidAccounts("correct_table_name", 'boo', 3);
CALL Bill_UpdateUnbalancedPrepaidAccounts("my-schema-name.correct_table_name", 'boo', 3);
All failed!
CREATE PROCEDURE Bill_UpdateUnbalancedPrepaidAccounts(prepAccTN VARCHAR(100), wtrTN VARCHAR(100), prepAccId INT)
BEGIN
UPDATE prepAccTN SET `unbalanced` = (
SELECT SUM(`chargesecs`) FROM wtrTN WHERE `prepaidaccount` = prepAccId AND `prepaccsettl` = 0
) WHERE `id` = prepAccId;
END//
DELIMITER ;
If you really need to pass ther table name as a parameter to a stored procedure you need to use prepared statements. You cannot use the parameter directly in a query.
Tried out the prepared statements but unfortunately they cannot be used within the stored procedure! So I do not use a SP now and put the whole necessary code (back) into the trigger. Not the best and preferred way but it's ok to me and my little sql code I have to execute
I am trying this but sure I am missing a lot
declare
my_id table.ISR_ID%type;
begin
select NVL(MAX(table.ISR_ID)+1,1) into isr_id
from table;
select my_pkg.getFunction(InputToFunction=> isr_id); -- from ?
end;
If you declared MY_ID variable, you should have selected into it, not into ISR_ID (which is never declared).
Also, you should return function's result into something (probably another variable?). I've declared it as FUN_RES - see the comment within the PL/SQL anonymous block.
Saying that you are missing a lot doesn't help much; you should specify which errors you get. Anyway: try such a code, say whether it works or not and - if not - say why not (possible errors, etc.).
declare
my_id table.ISR_ID%type;
fun_res number; --> function result should be returned into this variable.
-- I don't know what it returns, so I set it to be a NUMBER.
-- Change it, if necessary.
begin
select NVL(MAX(table.ISR_ID) + 1, 1)
into my_id
from table;
fun_res := my_pkg.getFunction(my_id);
end;
[EDIT]
If you have to select function's value for every ISR_ID in a table, then you don't need PL/SQL but
select isr_id,
my_pkg.getfunction(isr_id) fun_res
from table;
If you want PL/SQL, then do it in a loop, for example:
begin
for cur_r in (select isr_id from table) loop
dbms_output.put_line(cur_r.isr_id ||', result = ' || my_pkg.getfunction(cur_r.isr_id));
end loop;
end;
/
Recently, I deployed an Oracle WareHouse Builder (OWB) mapping. In the scenario I'm working right now, this mapping (ETL process) needs to be fired up by a trigger after an Update statement takes place on the fact table (working with WriteBack values).
As the mapping is deployed to the target schema as a package, the trigger must call the main procedure that OWB creates for the package. At first I didn't knew how to accomplish this task, but SQL Developer gave me a hint:
So, I took this code and put it inside my trigger. Like this:
CREATE OR REPLACE TRIGGER RESPALDO_HISTORIAL
AFTER UPDATE ON MONITOR_FT_TAB
FOR EACH ROW
DECLARE
P_STATUS VARCHAR2(200);
P_MAX_NO_OF_ERRORS VARCHAR2(200);
P_COMMIT_FREQUENCY VARCHAR2(200);
P_OPERATING_MODE VARCHAR2(200);
P_BULK_SIZE VARCHAR2(200);
P_AUDIT_LEVEL VARCHAR2(200);
P_PURGE_GROUP VARCHAR2(200);
P_JOB_AUDIT VARCHAR2(200);
BEGIN
P_MAX_NO_OF_ERRORS := NULL;
P_COMMIT_FREQUENCY := NULL;
P_OPERATING_MODE := NULL;
P_BULK_SIZE := NULL;
P_AUDIT_LEVEL := NULL;
P_PURGE_GROUP := NULL;
P_JOB_AUDIT := 'TRUE';
SINIESTROS_MARCADOS_MAP.MAIN(
P_STATUS => P_STATUS,
P_MAX_NO_OF_ERRORS => P_MAX_NO_OF_ERRORS,
P_COMMIT_FREQUENCY => P_COMMIT_FREQUENCY,
P_OPERATING_MODE => P_OPERATING_MODE,
P_BULK_SIZE => P_BULK_SIZE,
P_AUDIT_LEVEL => P_AUDIT_LEVEL,
P_PURGE_GROUP => P_PURGE_GROUP,
P_JOB_AUDIT => P_JOB_AUDIT
);
:P_STATUS := P_STATUS;
END RESPALDO_HISTORIAL;
/
When I tried to compile this trigger, I got this screen:
In this screen I tried clicking "Aplicar" (Apply in spanish) with and without the NULL checkbox, always getting this output:
TRIGGER RESPALDO_HISTORIAL compilado
Errors: check compiler log
Then I ran the SHOW ERRORS command and I got this:
33/3 PLS-00049: bad bind variable 'P_STATUS'
Now I don't quite understand these bind variables. If this is the code generated by SQL Developer to run the package, then why I get this error??
Please help! I need some guidelines in this matter!
Greetings!
A colon preceding a variable indicates that that variable is a bind variable. Bind variables of this type are typically used to pass values in and out of anonymous blocks. They're not allowed in procedures, functions, or triggers. In this case, you need to remove the line :P_STATUS := P_STATUS;.
I am trying to write a following PL/SQL function body for a dynamic action
The purpose of dynamic action is to set value for text area based on input parameters. Way I am trying to do it, is that setting the value into variable for different options
declare
P_NOTE varchar(100); -- derive value
P_WEBSERVER varchar(100); -- derive name
begin
-- for getting the P_NOTE value
select distinct note into P_NOTE from port_mapping where PLATFORM = :P3_PLATFORM and VERSION = :P3_VERSION;
-- for getting web server value
select CONCAT(P_NOTE,CONCAT('https-',:P3_CLIENT)) into P_WEBSERVER from dual order by 1;
if (:P3_PLATFORM = 'Apache') then
return P_WEBSERVER;
end if;
end;
However I am getting error
ORA-06550: line 15, column 5:
PLS-00372: In a procedure, RETURN statement cannot contain an expression
ORA-06550: line 15, column 5:
PL/SQL: Statement ignored
declare
P_NOTE varchar(100);
P_WEBSERVER varchar(100);
I am not sure what I am missing.
(Since you did not post any apex version this explanation deals with version 4.2)
If this -is- a dynamic action and the code you posted is in a true action of type 'Execute PL/SQL Code' then you can not use RETURN. The plsql block is not a function body (close, Mr Kemp!).
If you want to return values from the session state to page items then you need to use the "Page Items to Return" item of the true action.
This will put the session state of the defined page items into the value of the item on the page. This means that you can not use any variable to just put stuff in to be able to return it to the page, but you need to use an actual page item (after all, these are bind variables).
To clarify further, you would not write :
return P_WEBSERVER;
But you'd have to use a page item, say P3_WEBSERVER, and you'll need to create one if it doesn't exist of course:
:P3_WEBSERVER := p_webserver;
Of course you'd need to make sure that the correct value will be in there as you can not shortcircuit as you did in your code sample (p_webserver will usually hold a value even if the platform is not 'Apache') eg:
if (:P3_PLATFORM = 'Apache') then
:P3_WEBSERVER := P_WEBSERVER;
else
:P3_WEBSERVER := NULL;
end if;
Just read error message:
line 15, column 5
So, trouble caused by this line:
return P_WEBSERVER;
return not allowed in PL/SQL blocks, use output parameter to return a value.
Read Tom's answer to find out how to do that.