inserting parameters from select into procedure - oracle

I've got this select :
SELECT gp.name, gda.value
FROM game_definition_aff gda,
GAME_PARAMETAR gp,
game_aff ga,
game_name gn
WHERE 4355 = ga.aff_id
AND ga.id = gda.game_aff_id
AND gp.id = gda.game_parametar_id
AND 15 = ga.game_name_id
AND gn.game_name_id = ga.game_name_id
and gp.name in ( 'MIN_BET','MAX_BET','MAX_WIN')
which returns :
NAME - VALUE
MAX_WIN - 100
MAX_BET - 50
MIN_BET - 10
And i've got procedure :
get_percentage (i_player_id, o_session_id, royal_tri_win, o_percentage,
o_min_bet,
o_max_bet,
o_max_win,
o_pot
);
Now I need to insert values from select max_win,max_bet and min_bet into procedures parameters o_max_win,o_max_bet and o_bet_bet..
How can I do that ?
PS. this is procedure where is this code from above. and where are defined all parameters that is used in it..
PROCEDURE open_session_3w (
i_player_id NUMBER,
old_session_id NUMBER,
i_ip_address VARCHAR2,
i_machine_number VARCHAR2,
o_last_bet OUT NUMBER,
o_min_bet OUT NUMBER,
o_max_bet OUT NUMBER,
o_max_win OUT NUMBER,
o_credits OUT NUMBER,
o_session_id OUT NUMBER,
o_state OUT VARCHAR2
)
IS
o_percentage NUMBER;
o_pot NUMBER;
pom weak_cur;
p_active_session NUMBER;
p_parent number;
v_max_win number;
v_min_bet number;
v_max_bet number;
BEGIN
select parent_id into p_parent from casino_users where party_id = i_player_id;
check_pl_sess_3w (i_player_id, old_session_id);
o_session_id :=
player.open_new_session (i_player_id, i_ip_address,i_machine_number,'GAME SESSION');
select MAX( CASE WHEN gp.name = 'MAX_WIN' THEN VALUE END ),
MAX( CASE WHEN gp.name = 'MAX_BET' THEN VALUE END ),
MAX( CASE WHEN gp.name = 'MIN_BET' THEN VALUE END )
INTO v_max_win,v_max_bet,v_min_bet
FROM game_definition_aff gda,
GAME_PARAMETAR gp,
game_aff ga,
game_name gn
WHERE i_player_id = ga.aff_id
AND ga.id = gda.game_aff_id
AND gp.id = gda.game_parametar_id
AND 15 = ga.game_name_id
AND gn.game_name_id = ga.game_name_id
and gp.name in ( 'MIN_BET','MAX_BET','MAX_WIN') ;
player.get_percentage (i_player_id,
o_session_id,
royal_tri_win,
o_percentage,
COALESCE(v_min_bet,o_min_bet),
COALESCE(v_max_bet,o_max_bet),
COALESCE(v_max_win,o_max_win),
o_pot
);

Use MAX(CASE WHEN) and store each value in 3 variables.
DECLARE
v_max_win NUMBER;
v_max_bet NUMBER;
v_min_bet NUMBER;
BEGIN
select MAX( CASE WHEN gp.name = 'MAX_WIN' THEN VALUE END ),
MAX( CASE WHEN gp.name = 'MAX_BET' THEN VALUE END ),
MAX( CASE WHEN gp.name = 'MIN_BET' THEN VALUE END )
INTO v_max_win,v_max_bet,v_min_bet
FROM
game_definition_aff gda,
GAME_PARAMETAR gp,
game_aff ga,
game_name gn
..
..
get_percentage (i_player_id, o_session_id, royal_tri_win, o_percentage,
COALESCE( v_min_bet,o_min_bet),
COALESCE( v_max_bet,o_min_bet),
COALESCE( v_min_win,o_max_win),
o_pot
);
END;
/
Alternatively if you want to avoid local variables, you may use implicit cursor loop.
for rec in ( --select query above )
LOOP
get_percentage (i_player_id, o_session_id, royal_tri_win, o_percentage,
COALESCE( rec.min_bet,o_min_bet),
COALESCE( rec.max_bet,o_min_bet),
COALESCE( rec.min_win,o_max_win),
pot
);
END LOOP;

Related

Procedure is not ending

I am very new to PLSQL and stack overflow. I've written PLSQL code to post dummy entries in my assignment. I've wrote following code to post entries using dynamic SQL (I've read about it on this forum and internet and tried to use it). One of the issue I'm facing is that this procedure is not ending/exiting. I've looked into it multiple times but code seems find to me.
Could you please suggest what needs to be updated so I can post entries successfully?
Thanks in advance for kind help.
PS: This is my first question here. Please let me know if any updates are required.
--package spec
CREATE OR REPLACE PACKAGE POST_ENTRIES AS
PROCEDURE POST_DAILY() ;
PROCEDURE IN_LEDGER_STAT_DAILY
(
V_IDENTITY_CODE NUMBER,
V_CONSOLIDATION_CD NUMBER,
V_FINANCIAL_ELEM_ID NUMBER,
V_ORG_UNIT_ID NUMBER,
V_GL_ACCOUNT_ID NUMBER,
V_COMMON_COA_ID NUMBER,
V_PRODUCT_1_ID NUMBER,
V_PRODUCT_ID NUMBER,
V_PRODUCT_3_ID NUMBER,
V_DATE DATE,
V_AMOUNT NUMBER,
V_MEMO_GL_ACCOUNT_ID NUMBER DEFAULT 0,
V_POSTINGTYPE CHAR DEFAULT 'N',
V_BALANCE_TYPE_CD NUMBER DEFAULT 0
);
END POST_ENTRIES;
/
--package body
CREATE OR REPLACE PACKAGE BODY POST_ENTRIES AS
PROCEDURE POST_DAILY() AS
--BASE VARIABLES
i number := 0;
DS NUMBER := 82;
j number;
V_NEXT_WORKING_DATE DATE;
V_IDENTITY_CODE CONSTANT NUMBER(6):=112233;
V_CONSOLIDATION_CD CONSTANT NUMBER(3):=100;
v_RECORDS_EXPECTED number;
v_RECORDS_ACTUAL number;
-- variables store result of dynamic cursor
V_SQL VARCHAR2(2500);
TYPE V_CURSOR IS REF CURSOR;
seq V_CURSOR;
V_ORG_UNIT_ID LEDGER_STAT_DLY.ORG_UNIT_ID%TYPE;
V_GL_ACCOUNT_ID LEDGER_STAT_DLY.GL_ACCOUNT_ID%TYPE;
V_CMN_COA_ID LEDGER_STAT_DLY. COMMON_COA_ID%TYPE;
V_PROD1 LEDGER_STAT_DLY.PRODUCT_1_ID%TYPE;
V_PROD2 LEDGER_STAT_DLY.PRODUCT_ID%TYPE;
V_PROD3 LEDGER_STAT_DLY.PRODUCT_3_ID%TYPE;
V_DATE DAILYGL.AS_OF_DATE%TYPE;
V_POSTED APPLICATION_TABLE_RECORD_COUNT.DLY_AS_OF_DATE%TYPE;
V_UPPER number;
V_DATE_PARAM DATE;
V_END_BAL NUMBER;
V_AVG_BAL NUMBER;
V_SWITCH NUMBER(1);
V_FLAG AL_LOOKUP.FLAG1%TYPE;
V_FIN AL_LOOKUP.FIN_ELEM%TYPE;
V_FIN1 AL_LOOKUP.FIN_ELEM%TYPE;
V_ACCT_TYPE NUMBER(2);
BEGIN
V_DATE:= '31-may-2019' -- this is getting returned from function but I've placed value here directly.
V_NEXT_WORKING_DATE := '03-Jun-2019' -- this is getting returned from function but I've placed value here directly.
V_DATE_PARAM := V_DATE ; --POSTING DATE, START WITH V_DATE IT WILL INCREMENT INSIDE WHILE LOOP. EXIT WHEN V_DATE_PARAM = V_NEXT_WORKING_DATE
------------------------------
WHILE V_DATE_PARAM < V_NEXT_WORKING_DATE
loop
V_SQL := 'SELECT A.ACCOUNT_TYPE, B.FIN_ELEM, A.ORG_UNIT_ID, A.GL_ACCOUNT_ID, B.CMN_COA_ID, B.PROD1, B.PROD2, B.PROD3,
SUM(CURRENT_BAL) AS CB_SUM, SUM(AVG_BAL) AS AB_SUM, B.FLAG1 FROM DAILYGL_TEST A, AL_LOOKUP B
WHERE A.GL_ACCOUNT_ID = B.GL_ACCT AND A.AS_OF_DATE = '||chr(39)||V_DATE||chr(39)||
' and rownum <=3 GROUP BY A.ACCOUNT_TYPE, B.FIN_ELEM, A.ORG_UNIT_ID, A.GL_ACCOUNT_ID,B.CMN_COA_ID, B.PROD1,
B.PROD2, B.PROD3, A.AS_OF_DATE, B.FLAG1';
OPEN seq FOR V_SQL;
LOOP
V_SWITCH := 1;
FETCH seq INTO
V_ACCT_TYPE,
V_FIN,
V_ORG_UNIT_ID,
V_GL_ACCOUNT_ID,
V_CMN_COA_ID,
V_PROD1,
V_PROD2,
V_PROD3,
V_END_BAL,
V_AVG_BAL,
V_FLAG;
IF V_FLAG = 'Y' THEN
V_SWITCH := -1;
ELSE
V_SWITCH := 1;
END IF;
IF V_ACCT_TYPE = 5 OR V_ACCT_TYPE = 10 OR V_ACCT_TYPE = 20 OR V_ACCT_TYPE = 35 THEN
V_SWITCH := V_SWITCH * -1;
END IF;
IF (V_END_BAL <> 0 OR V_AVG_BAL <>0) THEN
IF V_ACCT_TYPE = 1 OR V_ACCT_TYPE = 5 OR V_ACCT_TYPE = 10 OR V_ACCT_TYPE = 90 THEN
V_FIN1 := SUBSTR(V_FIN,1,2) || '100';
IN_LEDGER_STAT_DAILY(V_IDENTITY_CODE,V_CONSOLIDATION_CD,V_FIN1,V_ORG_UNIT_ID,V_GL_ACCOUNT_ID,V_CMN_COA_ID,
V_PROD1, V_PROD2, V_PROD3,V_DATE_PARAM ,V_SWITCH * V_END_BAL);
IN_LEDGER_STAT_DAILY(V_IDENTITY_CODE,V_CONSOLIDATION_CD,V_FIN,V_ORG_UNIT_ID,V_GL_ACCOUNT_ID,V_CMN_COA_ID,
V_PROD1, V_PROD2, V_PROD3,V_DATE_PARAM,V_SWITCH * V_AVG_BAL);
ELSE
IN_LEDGER_STAT_DAILY(V_IDENTITY_CODE,V_CONSOLIDATION_CD,V_FIN,V_ORG_UNIT_ID,V_GL_ACCOUNT_ID,V_CMN_COA_ID,
V_PROD1, V_PROD2, V_PROD3,V_DATE_PARAM,V_SWITCH * V_END_BAL);
END IF;
END IF;
END LOOP;
CLOSE seq;
V_DATE_PARAM := V_DATE_PARAM +1;
end loop;
END POST_DAILY;
-------IN_LEDGER_STAT_DAILY procedure
PROCEDURE IN_LEDGER_STAT_DAILY
(
V_IDENTITY_CODE NUMBER,
V_CONSOLIDATION_CD NUMBER,
V_FINANCIAL_ELEM_ID NUMBER,
V_ORG_UNIT_ID NUMBER,
V_GL_ACCOUNT_ID NUMBER,
V_COMMON_COA_ID NUMBER,
V_PRODUCT_1_ID NUMBER,
V_PRODUCT_ID NUMBER,
V_PRODUCT_3_ID NUMBER,
V_DATE DATE,
V_AMOUNT NUMBER,
V_MEMO_GL_ACCOUNT_ID NUMBER DEFAULT 0,
V_POSTINGTYPE CHAR DEFAULT 'N',
V_BALANCE_TYPE_CD NUMBER DEFAULT 0
)
IS
V_CNT NUMBER;
V_D NUMBER;
V_DAY CHAR(6);
V_MONTH CHAR(2);
V_MO NUMBER;
V_YEAR_S NUMBER;
-- variables store result of dynamic cursor
V_SL VARCHAR2(2500);
V_TARGET_COLUMN VARCHAR2(6 CHAR);
k number := 0;
BEGIN
IF V_POSTINGTYPE = 'N' THEN
IF NVL(V_AMOUNT,0) <> 0 THEN
V_MO := (MONTH(V_DATE));
V_MONTH := LPAD(V_MO,2,'0');
V_YEAR_S := (YEAR(V_DATE));
V_D := (DAY(V_DATE));
V_DAY := 'DAY_' || lpad(V_D, 2, '0');
SELECT /*+ index(a LEDGER_STAT_DLY_IDX02_IN) */
COUNT(*) INTO V_CNT
FROM LEDGER_STAT_DLY A
WHERE
IDENTITY_CODE = NVL(V_IDENTITY_CODE,0)
AND YEAR_S = NVL(V_YEAR_S,0)
AND MONTH_NO = NVL(V_MONTH,0)
AND CONSOLIDATION_CD = NVL(V_CONSOLIDATION_CD,0)
AND FINANCIAL_ELEM_ID = NVL(V_FINANCIAL_ELEM_ID,0)
AND ORG_UNIT_ID = NVL(V_ORG_UNIT_ID,0)
AND GL_ACCOUNT_ID = NVL(V_GL_ACCOUNT_ID,0)
AND COMMON_COA_ID = NVL(V_COMMON_COA_ID,0)
AND PRODUCT_1_ID = NVL(V_PRODUCT_1_ID,0)
AND PRODUCT_ID = NVL(V_PRODUCT_ID,0)
AND PRODUCT_3_ID = NVL(V_PRODUCT_3_ID,0)
AND COST_TYPE_ID = NVL(V_MEMO_GL_ACCOUNT_ID,0)
AND BALANCE_TYPE_CD = NVL(V_BALANCE_TYPE_CD,0) ;
IF V_CNT = 0 THEN
INSERT INTO LEDGER_STAT_DLY VALUES(
NVL(V_IDENTITY_CODE,0),
NVL(V_YEAR_S,0) ,
NVL(V_MONTH,0) ,
'D',
NVL(V_CONSOLIDATION_CD,0),
NVL(V_FINANCIAL_ELEM_ID,0),
NVL(V_ORG_UNIT_ID,0) ,
NVL(V_GL_ACCOUNT_ID,0) ,
NVL(V_COMMON_COA_ID,0) ,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
NVL(V_PRODUCT_1_ID,0) ,
NVL(V_PRODUCT_ID,0) ,
NVL(V_PRODUCT_3_ID,0) ,
TRUNC(NVL(V_ORG_UNIT_ID,0) / 10000000),
'USD', -- ISO_CURRENCY_CD
NULL, -- CURRENCY_TYPE_CD
NVL(V_BALANCE_TYPE_CD,0),
0, -- VOLUME_ID
NVL(V_MEMO_GL_ACCOUNT_ID,0), -- COST_TYPE_ID
0 -- CHANNEL_ID
);
END IF;
EXECUTE IMMEDIATE UTL_LMS.FORMAT_MESSAGE('UPDATE /*+ index(a LEDGER_STAT_DLY_IDX02_IN) */ LEDGER_STAT_DLY A
SET %s = NVL(%s,0) + NVL(:THE_AMOUNT,0)
WHERE IDENTITY_CODE = NVL(:THE_IDENTITY_CODE,0)
AND YEAR_S = NVL(:THE_YEAR_S,0)
AND MONTH_NO = NVL(:THE_MONTH,0)
AND CONSOLIDATION_CD = NVL(:THE_CONSOLIDATION_CD,0)
AND FINANCIAL_ELEM_ID = NVL(:THE_FINANCIAL_ELEM_ID,0)
AND ORG_UNIT_ID = NVL(:THE_ORG_UNIT_ID,0)
AND GL_ACCOUNT_ID = NVL(:THE_GL_ACCOUNT_ID,0)
AND COMMON_COA_ID = NVL(:THE_COMMON_COA_ID,0)
AND PRODUCT_1_ID = NVL(:THE_PRODUCT_1_ID,0)
AND PRODUCT_ID = NVL(:THE_PRODUCT_ID,0)
AND PRODUCT_3_ID = NVL(:THE_PRODUCT_3_ID,0)
AND COST_TYPE_ID = NVL(:THE_MEMO_GL_ACCOUNT_ID,0)
AND BALANCE_TYPE_CD = NVL(:THE_BALANCE_TYPE_CD,0)', V_DAY, V_DAY)
USING V_AMOUNT, V_IDENTITY_CODE, V_YEAR_S, V_MONTH, V_CONSOLIDATION_CD, V_FINANCIAL_ELEM_ID, V_ORG_UNIT_ID,
V_GL_ACCOUNT_ID, V_COMMON_COA_ID, V_PRODUCT_1_ID, V_PRODUCT_ID, V_PRODUCT_3_ID, V_MEMO_GL_ACCOUNT_ID, V_BALANCE_TYPE_CD;
END IF;
END IF;
END IN_LEDGER_STAT_DAILY;
END POST_ENTRIES ;
/
The loop in your first procedure never exits; you need to add something like
EXIT WHEN seq%NOTFOUND;
i.e:
...
OPEN seq FOR V_SQL;
LOOP
V_SWITCH := 1;
FETCH seq INTO
V_ACCT_TYPE,
V_FIN,
V_ORG_UNIT_ID,
V_GL_ACCOUNT_ID,
V_CMN_COA_ID,
V_PROD1,
V_PROD2,
V_PROD3,
V_END_BAL,
V_AVG_BAL,
V_FLAG;
EXIT WHEN seq%NOTFOUND;
IF V_FLAG = 'Y' THEN
...
As mentioned in comments, the cursor query in that procedure doesn't need to be dynamic; and you should be using actual dates rather than strings that then rely on implicit conversion and NLS settings - or at a minimum, explicit conversion between strings and dates.

Calcute percentage of every game in

I need to calculate percentage and accumulate it from every game in. I have to parameters p_percentage which is gonna be variable and parameter p_top is also variable and his task is when p_top is satisfied then do something (update or insert) . I get lost here in loop . Is it better to do loop or fetch into v_percentage. And Am I doing it right ?
Thanks
CREATE OR REPLACE FUNCTION "jackpot"
(p_percentage number
,p_top number,
p_player number,
p_party_id number
)
RETURN NUMBER
declare
Cursor c1 is
select p_percentage/game_in *100 into v_percentage from game
where player_id = p_player ;
rw c1%rowtype;
v_top number;
v_percentage number;
BEGIN
open c1;
FOR i IN c1
while v_percentage <= p_top
LOOP
v_percentage:=v_percentage+v_percentage;
end loop;
--update something
close c1;
return v_percentage;
END;
end;
EDIT
create or replace PROCEDURE super_six_jackpot (
i_party_id IN NUMBER,
i_jackpot_limit IN NUMBER,
i_jackpot_perc IN NUMBER,
o_pot_size OUT NUMBER
)
IS
p_username VARCHAR2(100);
p_party_id number;
pot_perc NUMBER;
pot_size NUMBER;
parent_aff NUMBER;
ret_pot_size NUMBER;
pom weak_cur;
BEGIN
SELECT c.party_id, p.aff_id
into p_party_id, parent_aff
FROM casino_users c,pot_by_aff p
WHERE c.parent_id = p.aff_id
AND c.parent_id = :i_party_id;
SELECT total
INTO pot_perc
FROM (
SELECT SUM( i_jackpot_perc/game_in * 100 ) OVER ( ORDER BY ROWNUM ) AS total
FROM game_record
WHERE party_id = p_party_id
ORDER BY total DESC
)
WHERE total <= i_jackpot_limit
AND ROWNUM = 1;
EXECUTE IMMEDIATE 'UPDATE pot_by_aff
SET bingo_jackpot_size = NVL (total, 0)
WHERE aff_id = :parent_aff
RETURNING pot_size
INTO :ret_pot_size'
USING parent_aff,
OUT ret_pot_size;
BEGIN
OPEN pom FOR 'SELECT bingo_jackpot_size
FROM pot_by_aff
WHERE aff_id = :parent_aff'
USING parent_aff;
FETCH pom
INTO ret_pot_size;
CLOSE pom;
END;
o_pot_size := ret_pot_size;
END super_six_jackpot;
Do you simply need to know whether the total percentage for a player reaches or exceeds the top? For that you could use the SUM function in a single SQL statement, no loop. I don't know where game_in comes from, and why you would use p_percentage inside the SELECT, but perhaps this helps:
CREATE OR REPLACE PROCEDURE give_jackpot (p_percentage NUMBER,
p_top NUMBER,
p_player NUMBER,
p_party_id NUMBER)
IS
l_total NUMBER;
BEGIN
SELECT SUM (p_percentage / game_in * 100)
INTO l_total
FROM game
WHERE player_id = p_player;
IF l_total >= p_top
THEN
/* insert or update here */
NULL;
END IF;
END;
Use an analytic function to get the cumulative total in the SQL query.
You do not use DECLARE with specifying a procedure.
Do not use double quoted identifiers if you do not have to.
You cannot use SELECT ... INTO within a cursor.
Like this:
CREATE OR REPLACE FUNCTION jackpot (
p_percentage number,
p_top number,
p_player number,
p_party_id number
) RETURN NUMBER
IS
v_percentage number;
BEGIN
SELECT total
INTO v_percentage
FROM (
SELECT SUM( p_percentage/game_in *100 ) OVER ( ORDER BY ROWNUM ) AS total
FROM game
WHERE player_id = p_player
ORDER BY total DESC
)
WHERE total <= p_top
AND ROWNUM = 1;
--update something
RETURN v_percentage;
END;
/

Dynamic where clause in ORACLE

The requirement is to fetch results from STUDENTS table.
If zero is passed in as student id,no more filtering on the studentid is required.
PROCEDURE getResults (
inStudentId IN NUMBER,
inSectionId IN NUMBER,
inRowLimit IN NUMBER,
outResultsData OUT gphResultsData
) AS
stStudentId VARCHAR2(50) := '';
BEGIN
outResultsData := gphResultsData();
IF inStudentId = '0' THEN
stStudentId := '%';
ELSE
stStudentId := TO_CHAR(inStudentId);
END IF;
FOR rResults IN (
SELECT
RESULTS.STUDENT_ID,
RESULTS.STUDENT_NAME
FROM
RESULTS
WHERE
RESULTS.STUDENT_ID LIKE stStudentId AND -- not a good idea
RESULTS.SECTION_ID = inSectionId AND
ROWNUM <= inRowLimit
) LOOP
outResultsData.extend;
outResultsData(outResultsData.last).studentId := rResults.STUDENT_ID;
outResultsData(outResultsData.last).studentName := rResults.STUDENT_NAME;
END LOOP;
EXCEPTION
WHEN others THEN
...
I have come up with the above solution - which is definitely not ideal as
inStudentId is converted to STRING using TO_CHAR and then subjected to LIKE.
I guess the better way would be to dynamically generate and execute the where clause. That is -
if inStudentId = 0 ,
SELECT
RESULTS.STUDENT_ID,
RESULTS.STUDENT_NAME
FROM
RESULTS
WHERE
RESULTS.SECTION_ID = inSectionId AND
ROWNUM <= inRowLimit
if inStudentId is not zero,
SELECT
RESULTS.STUDENT_ID,
RESULTS.STUDENT_NAME
FROM
RESULTS
WHERE
RESULTS.STUDENT_ID = inStudentId AND
RESULTS.SECTION_ID = inSectionId AND
ROWNUM <= inRowLimit
Any pointer on how to best solve this problem will be a great help.
Assuming you have the types:
CREATE TYPE gphResult IS OBJECT(
student_id INT,
student_name VARCHAR2(50)
);
/
CREATE TYPE gphResultsData IS TABLE OF gphResult;
/
Then you can avoid the loop using BULK COLLECT INTO like this:
PROCEDURE getResults (
inStudentId IN NUMBER,
inSectionId IN NUMBER,
inRowLimit IN NUMBER,
outResultsData OUT gphResultsData
) AS
stStudentId VARCHAR2(50) := '';
BEGIN
SELECT gphResult( STUDENT_ID, STUDENT_NAME )
BULK COLLECT INTO outResultsData
FROM RESULTS
WHERE ( inStudentId = 0 OR student_id = inStudentId )
AND SECTION_ID = inSectionId
AND ROWNUM <= inRowLimit;
EXCEPTION
WHEN others THEN
...
I think the easiest way to do it is the following:
PROCEDURE getResults (
inStudentId IN NUMBER,
inSectionId IN NUMBER,
inRowLimit IN NUMBER,
outResultsData OUT gphResultsData
) AS
BEGIN
outResultsData := gphResultsData();
FOR rResults IN (
SELECT
RESULTS.STUDENT_ID,
RESULTS.STUDENT_NAME
FROM
RESULTS
WHERE
(RESULTS.STUDENT_ID = inStudentId OR inStudentId = 0) AND
RESULTS.SECTION_ID = inSectionId AND
ROWNUM <= inRowLimit
) LOOP
outResultsData.extend;
outResultsData(outResultsData.last).studentId := rResults.STUDENT_ID;
outResultsData(outResultsData.last).studentName := rResults.STUDENT_NAME;
END LOOP;
EXCEPTION
WHEN others THEN
...

How to optimize my stored procedure

I would like to know if there are ways I could optimize n improve performance of this stored procedure. I'm fairly new at it & would appreciate your help
To summary , the stored procedure takes an array . Each array an entry of the form a:b:c . After extracting the required data, an entry is made in a table.
create or replace
PROCEDURE insert_sku_prom_assigments (
sku_assigment_array tp_string_array_table
)
IS
first_colon_pos NUMBER;
second_colon_pos NUMBER;
sku VARCHAR2 (40);
assign VARCHAR2 (20);
promotion VARCHAR2 (40);
l_count INTEGER;
BEGIN
FOR i IN sku_assigment_array.FIRST .. sku_assigment_array.LAST
LOOP
first_colon_pos := INSTR (sku_assigment_array (i), ':', 1, 1);
second_colon_pos := INSTR (sku_assigment_array (i), ':', 1, 2);
sku := SUBSTR (sku_assigment_array (i), 1, first_colon_pos - 1);
assign :=
SUBSTR (sku_assigment_array (i),
first_colon_pos + 1,
second_colon_pos - first_colon_pos - 1
);
promotion := SUBSTR (sku_assigment_array (i), second_colon_pos + 1);
IF sku IS NOT NULL AND assign IS NOT NULL AND promotion IS NOT NULL
THEN
SELECT COUNT (*)
INTO l_count
FROM mtep_sku_promotion_rel_unver
WHERE sku_id = sku
AND assignment = assign
AND promotion_id = promotion
AND ROWNUM = 1;
IF l_count < 1
THEN
INSERT INTO mtep_sku_promotion_rel_unver
(sku_id, assignment, promotion_id
)
VALUES (sku, assign, promotion
);
END IF;
END IF;
l_count := 0;
END LOOP;
END insert_sku_prom_assigments;
#jorge is right there probably isn't much performance improvement to be found. But you could consider these alternatives to selecting a count before inserting:
This:
INSERT INTO mtep_sku_promotion_rel_unver
(sku_id, assignment, promotion_id
)
SELECT sku, assign, promotion FROM DUAL
WHERE NOT EXISTS
( SELECT NULL
FROM mtep_sku_promotion_rel_unver
WHERE sku_id = sku
AND assignment = assign
AND promotion_id = promotion
);
Or, assuming those 3 columns are defined as a key:
BEGIN
INSERT INTO mtep_sku_promotion_rel_unver
(sku_id, assignment, promotion_id
)
VALUES (sku, assign, promotion
);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN NULL;
END;
This is not performance-related, but I also like to use the Oracle function apex_util.string_to_table to break up delimited strings easily:
PROCEDURE ...
IS
v_tab apex_application_global.vc_arr2;
...
BEGIN
v_tab := apex_util.string_to_table (sku_assigment_array (i), ':');
if v_tab.count >= 3 then
sku := v_tab(1);
assign := v_tab(2);
promotion := v_tab(3);
end if;
Replace the row-by-row PL/SQL with a single SQL statement:
create or replace procedure insert_sku_prom_assigments
(
sku_assigment_array tp_string_array_table
) is
begin
--#4: Insert new SKU, ASSIGN, and PROMOTION.
insert into mtep_sku_promotion_rel_unver(sku_id, assignment, promotion_id)
select sku, assign, promotion
from
(
--#3: Get values.
select sku_string,
substr (sku_string, 1, first_colon_pos - 1) sku,
substr (sku_string, first_colon_pos + 1, second_colon_pos-first_colon_pos - 1) assign,
substr (sku_string, second_colon_pos + 1) promotion
from
(
--#2: Get positions.
select
sku_string,
instr(sku_string, ':', 1, 1) first_colon_pos,
instr(sku_string, ':', 1, 2) second_colon_pos
from
(
--#1: Convert collection to table.
select column_value sku_string
--Use this for debugging:
--from table(tp_string_array_table('asdf:qwer:1234'))
from table(sku_assigment_array)
) converted_collection
) positions
) sku_values
--Only non-null values:
where sku is not null and assign is not null and promotion is not null
--Row does not already exist:
and not exists
(
select 1/0
from mtep_sku_promotion_rel_unver
where sku_id = sku
and assignment = assign
and promotion_id = promotion
);
end insert_sku_prom_assigments;
/
Here are sample objects for testing:
create or replace type tp_string_array_table is table of varchar2(4000);
create table mtep_sku_promotion_rel_unver(
sku_id varchar2(100),
assignment varchar2(100),
promotion_id varchar2(100));
begin
insert_sku_prom_assigments(tp_string_array_table('asdf:qwer:1234'));
end;
/
SQL almost always outperforms PL/SQL. It's also easier to test and debug once you get used to the way the code flows.

How to declare a Cursors With different conditions

I have a procedure EMPHIRESEPCHAN which is used to fetch the employees list who are hired, seperated and changed their titles based on a particular time frame. The procedure is as follows:
PROCEDURE EMPHIRESEPCHAN ( p_Start in VarChar2, p_End in VarChar2,
p_Hire IN VarChar2, p_Sep IN VarChar2, p_Changed IN VarChar2, p_Condition1 IN VarChar2, p_Condition2 IN VarChar2)
IS
CURSOR c_emplst ( p_listtype varchar2 ) IS
select e.emp_id, e.name, e.Rank
from person.emp e
where emp_id in (select distinct(emp_id) from person.promo
where pdate between p_startDate and p_endDate
and dcode in
(select adj from support.descr where typ = 'PROMO' and smeaning = p_listtype) );
CURSOR c_promolst ( p_emp_id varchar2 ) IS
select pdate
from person.promo
where emp_id = p_emp_id
order by 2 desc;
Begin
for EmpRec in c_emplst ('HIRE')
LOOP
for PromoRec in c_PromoLst ( EmpRec.emp )
LOOP
if PromoRec.Dcode in ('TEMPORARY','RETURN','APPOINTED' )
-- Do all the operation
end if;
end loop;
end loop;
end EMPHIRESEPCHAN;
I have to modify the procedure to retrieve the employee list based on p_Condition1 and p_Condition2 parameters.
If the p_Condition1 is not null and p_Condition2 is null, I have to retrieve the employees who have Rank = 'Developer'
If the p_Condition1 is null and p_Condition2 is not null I have to retrieve the employees who have Rank = 'Tester'
If the p_Condition1 and p_Condition2 is not null I have to retrieve the employees who have Rank both 'Developer' and 'Tester'.
I read so many posts in various sites and found answers which I was not able to follow.
Based on the posts, I made modifications to the cursor as follows
CURSOR c_emplst ( p_listtype varchar2 ) IS
select e.emp_id, e.name, e.Rank
from person.emp e
where ( p_Condition1 = null and p_Condition2 = null = and emp_id in (select distinct(emp_id) from person.promo
where pdate between p_startDate and p_endDate
and dcode in (select adj from support.descr where typ = 'PROMO' and smeaning = p_listtype) )
or ( p_Condition1 > null and p_Condition2 = null = and emp_id in (select distinct(emp_id) from person.promo
where pdate between p_startDate and p_endDate
and Rank ='Developer'
and dcode in (select adj from support.descr where typ = 'PROMO' and smeaning = p_listtype) )
or ( p_Condition1 = null and p_Condition2 > null = and emp_id in (select distinct(emp_id) from person.promo
where pdate between p_startDate and p_endDate
and Rank = 'Tester'
and dcode in (select adj from support.descr where typ = 'PROMO' and smeaning = p_listtype) );
However it's not working.
Thanks for your time and consideration.
I suspect these conditions are your problem:
p_Condition1 = null
Nothing is ever equal to NULL. NULL is not even equal to NULL. Instead, use:
p_Condition1 IS NULL

Resources