I have a Package In Oracle Which Spools Customer Information. The Package is like:
EDIT
create or replace
PACKAGE mfi_statement_spool
AS
PROCEDURE mfi_main_spool (fromdate IN DATE, todate IN DATE,c1 out SYS_REFCURSOR,c2 out SYS_REFCURSOR);
FUNCTION mfi_cust_details (vforacid IN VARCHAR2)
RETURN VARCHAR2;
FUNCTION mfi_citycountry (vcountrycode IN VARCHAR2, vcitycode IN VARCHAR2)
RETURN VARCHAR2;
END mfi_statement_spool;
/
I need to use the Main_Spool Procedure Which I declared this way:
EDIT FULL PACKAGE BODY
CREATE OR REPLACE
PACKAGE BODY TBAADM.mfi_statement_spool
AS
-- --------------------------------------------------------------------------
PROCEDURE mfi_main_spool(
fromdate DATE,
todate DATE,
c1 OUT SYS_REFCURSOR,
c2 OUT SYS_REFCURSOR)
AS
cramount NUMBER;
dramount NUMBER;
countcr NUMBER;
countdr NUMBER;
srl_num NUMBER;
ledgerbal NUMBER;
c1 SYS_REFCURSOR;
c2 SYS_REFCURSOR;
opbal NUMBER;
vdocremarks VARCHAR2 (100);
vremarkscorporate VARCHAR2 (100);
vremarksretail VARCHAR2 (100);
remarks VARCHAR2 (100);
endbal NUMBER;
curamount NUMBER;
totaltrans NUMBER;
sumtrans NUMBER;
vtranamt VARCHAR2 (50);
state1 VARCHAR2 (600);
rnum NUMBER;
state2 VARCHAR2 (600);
state3 VARCHAR2 (600);
fuunclamt NUMBER;
state4 VARCHAR2 (600);
balancebf VARCHAR2 (50);
ebal VARCHAR2 (50);
lbal VARCHAR2 (50);
vinstrnumcheck VARCHAR2 (15);
vinstrnum VARCHAR2 (50);
vpaart VARCHAR2 (50);
wfile_handle UTL_FILE.file_type;
filename VARCHAR2(100);
CURSOR c1
IS
SELECT foracid,
acct_name,
addr_1,
addr_2,
sol_desc,
city_code,
gam.FUTURE_UN_CLR_BAL_AMT
FROM tbaadm.gam,
tbaadm.sol
WHERE gam.sol_id = sol.sol_id
AND schm_type IN ('CAA','ODA','LAA')
AND schm_code NOT IN ('CTSTF');
CURSOR c2 (vforacid VARCHAR2)
IS
SELECT TRIM (foracid),
tran_amt,
part_tran_type,
acct_name,
gam.cust_id,
clr_bal_amt,
gam.acid,
un_clr_bal_amt,
acct_crncy_code,
tran_date,
htd.value_date,
htd.instrmnt_num,
htd.tran_particular
FROM tbaadm.gam,
tbaadm.htd
WHERE gam.acid = htd.acid
AND foracid = vforacid
AND tran_date >= fromdate
AND tran_date <= todate
AND pstd_flg = 'Y'
AND htd.del_flg != 'Y'
AND acct_cls_flg != 'Y'
AND schm_type IN ('CAA','ODA','LAA')
AND schm_code NOT IN ('CTSTF')
ORDER BY foracid,
htd.pstd_date ;
BEGIN
FOR i IN c1
LOOP
rnum := 0;
filename := 'statement_' || TO_CHAR(i.foracid) || '.TXT';
wfile_handle := UTL_FILE.fopen ('DIR_TEMP', filename, 'W', 32767);
BEGIN
SELECT NVL (SUM (tran_date_bal), 0)
INTO opbal
FROM tbaadm.gam,
tbaadm.eab
WHERE gam.acid = eab.acid
AND gam.foracid = i.foracid
AND eod_date =
(SELECT MAX(eod_date)
FROM tbaadm.eab
WHERE eod_date < fromdate
AND acid IN
(SELECT acid FROM tbaadm.gam WHERE foracid=i.foracid
)
);
EXCEPTION
WHEN NO_DATA_FOUND THEN
opbal := 0;
END;
BEGIN
IF opbal < 0 THEN
SELECT REPLACE(concat(TO_CHAR(opbal,'9999999990D99') ,' DR'),'-')
INTO balancebf
FROM dual;
ELSE
SELECT concat(TO_CHAR(opbal,'9999999990D99') ,' CR') INTO balancebf FROM dual;
END IF;
END;
BEGIN
SELECT NVL (SUM (DECODE (part_tran_type, 'D', -1 * tran_amt, tran_amt ) ), 0 )
INTO sumtrans
FROM tbaadm.htd
WHERE acid =
(SELECT acid FROM tbaadm.gam WHERE foracid = i.foracid
)
AND pstd_flg = 'Y'
AND del_flg != 'Y'
AND tran_date >= fromdate
AND tran_date <= todate;
EXCEPTION
WHEN NO_DATA_FOUND THEN
sumtrans := 0;
END;
endbal := sumtrans + opbal;
BEGIN
IF endbal < 0 THEN
SELECT REPLACE(concat(TO_CHAR(endbal,'9999999990D99') ,' DR'),'-')
INTO ebal
FROM dual;
ELSE
SELECT concat(TO_CHAR(endbal,'9999999990D99') ,' CR') INTO ebal FROM dual;
END IF;
END;
BEGIN
SELECT NVL (SUM (DECODE (part_tran_type, 'D', 1, 0)), 0),
NVL (SUM (DECODE (part_tran_type, 'C', 1, 0)), 0)
INTO countdr,
countcr
FROM tbaadm.htd
WHERE acid IN
(SELECT acid FROM tbaadm.gam WHERE foracid = i.foracid
)
AND tran_date >= fromdate
AND tran_date <= todate
AND pstd_flg = 'Y'
AND del_flg != 'Y';
EXCEPTION
WHEN NO_DATA_FOUND THEN
countcr := 0;
countdr := 0;
END;
totaltrans := countcr + countdr;
FOR j IN c2 (i.foracid)
LOOP
rnum := rnum + 1;
SELECT TO_CHAR (DECODE (j.part_tran_type, 'C', j.tran_amt, '0.00'),'9999999990D99')
|| '|'
|| TO_CHAR (DECODE (j.part_tran_type, 'D', j.tran_amt, '0.00'),'9999999990D99')
INTO vtranamt
FROM DUAL;
SELECT DECODE (j.part_tran_type, 'D', -1 * j.tran_amt, j.tran_amt)
INTO curamount
FROM DUAL;
opbal := opbal + curamount;
IF opbal < 0 THEN
SELECT REPLACE(concat(TO_CHAR(opbal,'9999999990D99') ,' DR'),'-')
INTO lbal
FROM dual;
ELSE
SELECT concat(TO_CHAR(opbal,'9999999990D99') ,' CR') INTO lbal FROM dual;
END IF;
BEGIN
BEGIN
SELECT DISTINCT purgeremarks
INTO vremarksretail
FROM crmuser.accounts
WHERE orgkey =
(SELECT cif_id FROM tbaadm.cmg WHERE cmg.cust_id =j.cust_id
)
AND rownum < 2;
EXCEPTION
WHEN NO_DATA_FOUND THEN
vremarksretail := NULL;
END;
IF (vremarksretail IS NULL) THEN
BEGIN
SELECT DISTINCT remarks
INTO vremarkscorporate
FROM crmuser.corporate
WHERE corp_key =
(SELECT cif_id FROM tbaadm.cmg WHERE cmg.cust_id =j.cust_id
)
AND rownum < 2;
EXCEPTION
WHEN NO_DATA_FOUND THEN
vremarkscorporate := NULL;
END;
remarks := vremarkscorporate;
ELSE
remarks := vremarksretail;
END IF;
END;
BEGIN
SELECT DISTINCT docremarks
INTO vdocremarks
FROM crmuser.entitydocument
WHERE core_cust_id = j.cust_id
AND rownum < 2;
EXCEPTION
WHEN NO_DATA_FOUND THEN
vdocremarks := NULL;
END;
BEGIN
SELECT SUBSTR (j.tran_particular, 1, 7) INTO vinstrnumcheck FROM DUAL;
EXCEPTION
WHEN NO_DATA_FOUND THEN
vinstrnumcheck := NULL;
END;
IF (vinstrnumcheck = 'BY INST') THEN
vpaart := 'OUTWARD CLEARING KES';
ELSE
vpaart := j.tran_particular;
END IF;
IF (vinstrnumcheck = 'BY INST') THEN
SELECT SUBSTR (j.tran_particular, 8, (INSTR (j.tran_particular, ':') - 8) )
INTO vinstrnum
FROM DUAL;
ELSE
vinstrnum := j.instrmnt_num;
END IF;
BEGIN
SELECT FUTURE_UN_CLR_BAL_AMT
INTO fuunclamt
FROM tbaadm.gam g
WHERE g.foracid=i.foracid;
END;
BEGIN
UTL_FILE.put_line (wfile_handle, rnum || '|' || i.foracid || '|' || j.acct_crncy_code || '|' || j.tran_date || '|' || j.value_date || '|' || vinstrnum || '|' || vpaart || '|' || vtranamt || '|' || lbal || '|' || j.acct_name || '|' || mfi_cust_details (i.foracid) || '|' || ebal || '|' || countdr || '|' || countcr || '|' || j.un_clr_bal_amt || '|' || balancebf || '|' || fromdate || '|' || todate || '|' || todate || '|' || remarks || '|' || vdocremarks || '|' || fuunclamt );
END;
END LOOP;
rnum := rnum - 1;
UTL_FILE.fclose (wfile_handle);
END LOOP;
END mfi_main_spool;
-- ---------------------------------------------------------------------------
FUNCTION mfi_cust_details(
vforacid VARCHAR2)
RETURN VARCHAR2
IS
vcustdetails VARCHAR2 (300);
BEGIN
BEGIN
SELECT a.cust_title_code
|| '|'
|| a.cust_id
|| '|'
|| b.address_line1
|| '|'
|| b.address_line2
|| '|'
|| mfi_citycountry (b.country, b.city)
|| '|'
|| b.zip
INTO vcustdetails
FROM tbaadm.cmg a,
crmuser.address b
WHERE TRIM (a.cif_id) = TRIM (b.orgkey)
AND UPPER (b.addresscategory) IN ('MAILING', 'REGISTERED')
AND cust_id IN
(SELECT cust_id FROM gam WHERE foracid = vforacid
);
EXCEPTION
WHEN NO_DATA_FOUND THEN
vcustdetails := NULL || '|' || NULL || '|' || NULL || '|' || NULL || '|' || NULL || '|' || NULL || '|' || NULL;
END;
RETURN vcustdetails;
END mfi_cust_details;
FUNCTION mfi_citycountry(
vcountrycode VARCHAR2,
vcitycode VARCHAR2)
RETURN VARCHAR2
IS
vcountry VARCHAR2 (50);
vcity VARCHAR2 (50);
vcity_country VARCHAR2 (100);
BEGIN
BEGIN
SELECT ref_desc
INTO vcountry
FROM tbaadm.rct
WHERE ref_rec_type = '03'
AND ref_code = vcountrycode;
EXCEPTION
WHEN NO_DATA_FOUND THEN
vcountry := NULL;
END;
BEGIN
SELECT ref_desc
INTO vcity
FROM tbaadm.rct
WHERE ref_rec_type = '01'
AND ref_code = vcitycode;
EXCEPTION
WHEN NO_DATA_FOUND THEN
vcity := NULL;
END;
vcity_country := vcity || '|' || vcountry;
RETURN vcity_country;
END mfi_citycountry;
-- -----------------------------------------------------------------------
END mfi_statement_spool;
/
EDIT: THE ERROR IS STILL THERE
I have Two Cursors In the Procedure Above, Cursor 1 And Cursor Two. I have tried to add the Cursors into the declarations like:
...PROCEDURE mfi_main_spool (fromdate DATE, todate DATE,c1 out SYS_REFCURSOR,c2 out SYS_REFCURSOR).....
So that it I can use it with Jasper but the package Body does Not Compile with the Following Error:
PLS-00323: subprogram or cursor 'MFI_MAIN_SPOOL' is declared in a package specification and must be defined in the package body
Is there Something I am not doing Correctly?
You have to update your package specification first:
CREATE OR REPLACE PACKAGE mfi_statement_spool
AS
PROCEDURE mfi_main_spool (fromdate IN DATE, todate IN DATE,c1 out SYS_REFCURSOR,c2 out SYS_REFCURSOR);
FUNCTION mfi_cust_details (vforacid IN VARCHAR2)
RETURN VARCHAR2;
FUNCTION mfi_citycountry (vcountrycode IN VARCHAR2, vcitycode IN VARCHAR2)
RETURN VARCHAR2;
END mfi_statement_spool;
/
After that update your package body with the new parameters:
CREATE OR REPLACE PACKAGE BODY mfi_statement_spool
AS
-- --------------------------------------------------------------------------
PROCEDURE mfi_main_spool (fromdate DATE, todate DATE, c1 out SYS_REFCURSOR,c2 out SYS_REFCURSOR)
AS
cramount NUMBER;
dramount NUMBER;
BEGIN
OPEN c1 for
SELECT foracid,
acct_name,
addr_1,
addr_2,
sol_desc,
city_code,
gam.FUTURE_UN_CLR_BAL_AMT
FROM tbaadm.gam,
tbaadm.sol
WHERE gam.sol_id = sol.sol_id
AND schm_type IN ('CAA','ODA','LAA')
AND schm_code NOT IN ('CTSTF');
-- handle c2 the same way...
LOOP
FETCH c1 into v_foracid, v_acct_name, v_addr_1, ...;
EXIT WHEN c1%NOTFOUND;
-- do something with your variables here
END LOOP;
CLOSE c1;
-- same for c2 again...
END mfi_main_spool;
FUNCTION mfi_cust_details (vforacid IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
NULL;
-- do something here
END mfi_cust_details;
FUNCTION mfi_citycountry (vcountrycode IN VARCHAR2, vcitycode IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
NULL;
-- do something here
END mfi_citycountry;
END;
/
This way it's compiling fine for me.
For every procedure that is defined in your package specification, you have to have one procedure in your package body that is defined the same way, meaning it has the same name, expects the same parameters and has the same returntype if it's a function, etc.
But you can have more hidden procedures and functions in your body that can't be accessed from outside the package. They don't have to be defined in the package specification.
For a guide on SYS_REFCURSOR see here:
http://www.oracle-base.com/articles/misc/using-ref-cursors-to-return-recordsets.php or here:
http://www.oracle.com/technetwork/issue-archive/2013/13-mar/o23plsql-1906474.html
Hi
It seems that the procedure signature in
package specification is different from the package body.
These two should match exactly. You can try like this.
It should work. Thanks
CREATE OR REPLACE PACKAGE TBAADM.mfi_statement_spool
AS
PROCEDURE mfi_main_spool (fromdate IN DATE,
todate IN DATE,
c1 out SYS_REFCURSOR,
c2 out SYS_REFCURSOR);
FUNCTION mfi_cust_details (vforacid IN VARCHAR2)
RETURN VARCHAR2;
FUNCTION mfi_citycountry (vcountrycode IN VARCHAR2, vcitycode IN VARCHAR2)
RETURN VARCHAR2;
END mfi_statement_spool;
/
CREATE OR REPLACE PACKAGE BODY TBAADM.mfi_statement_spool
AS
PROCEDURE mfi_main_spool (fromdate DATE, todate DATE)
AS
Begin
/* Stuff you want to do */
end mfi_main_spool;
/* definition of other procedures and function. */
end mfi_statement_spool;
Related
I select some rows in dbgrid and then have to pass set of values in parameter of stored procedure or query. I use Firebird 3. How to pass multiple values in a single parameter if number of values is not predefined? For example, for 3 values of good_id I get error:
conversion error from string "7802 ,8403 ,11461"
create or alter procedure sp_goods (id varchar(60))
returns (
good varchar(50),
good_id integer)
as
begin
for select good_id, good from goods where good_id in (:id)
into :good_id, :good
do suspend;
end
procedure Button1Click(Sender: TObject);
var
str : String;
i : Integer;
begin
Query1.Close;
Query1.SQL.Text := 'select * from sp_goods(:id) ';
with DBGridGoods do
begin
if SelectedRows.Count > 0 then
begin
str := '';
With DataSource.DataSet do
for i := 0 to SelectedRows.Count - 1 do
begin
GotoBookmark(SelectedRows.Items[i]) ;
str := str + FieldByName('good_id').asString + ', ';
end;
str := copy( str, 1, length( str ) - 2 );
end;
end;
Query1.Params[0].AsString:=str;
Query1.Open;
end;
If I call stored procedure in IBExpert
select * from sp_goods('8403')
It works, but
select * from sp_goods('8403','7802')
returns error
Input parameter mismatch for procedure sp_goods.
The same error occurs if I use query instead of stored procedure.
I tried to use array for values, but get empty dataset:
procedure Button1Click(Sender: TObject);
var
a: array of integer;
begin
Query1.Close;
Query1.SQL.Text := 'select * from sp_goods(:id) ';
setlength(a, 2);
a[0]:= 7802;
a[1]:=8403;
Query1.Params[0].Value:= a;
Query1.Open;
end;
There is no way to pass set of values into single parameter in Firebird.
In your example whole stored procedure is meaningless and it is simpler and faster to select all values at once into original grid using join. If you wish to get goods for selected items only and to put them into a separate grid the best way is to perform the query in your loop instead of gathering list of ids. If you prepare the query once (it is a common mistake to do prepare() call inside of the loop) it will be quite fast.
I have achieved this in two ways in the past. One is by using Dynamic Queries, which is not what you want to do, unless there is no other option.
The other way is by using this procedure. I am dragging this from my archives, and there will be other ways to achieve this more efficiently. I am providing it to show how to do it.
create or alter procedure "Split_Line"
( IP_NOTE VARCHAR (16000),
IP_SEP CHAR (1))
returns (
"Index" INTEGER,
"Line" VARCHAR (16000))
as
declare variable lLines varchar (16000);
declare variable lMax integer;
declare variable lPos integer;
begin
lMax = 16000;
lLines = ip_Note;
"Index" = 0;
while (lLines is not null)
do begin
"Line" = null;
lPos = null;
select "Result" from "Pos" (:Ip_Sep, :lLines) into :lPos;
if (lPos is null or lPos = 0)
then begin
/* Last line with no separator */
"Line" = lLines;
lLines = null;
end
else if (lPos = 1 and lLines = Ip_Sep)
then begin
/* Last char is a separator */
"Line" = '';
lLines = null;
end
else begin
/* Normal Case */
// "Line" = "SubStr" (:lLines, 1, :lPos-1);
// lLines = "SubStr" (:lLines, :lPos+1, :lMax);
"Line" = substring (:lLines from 1 for :lPos-1);
lLines = substring (:lLines from :lPos+1 for :lMax);
end
"Index" = "Index" + 1;
suspend;
end
end
You call it with a comma separated values in a string and the separator character (comma in this case). And it returns a table that you use.
Example of usage
select * from "Split_Line" ('x,a,cat', ',')
will return
Index
Line
1
x
2
a
3
cat
And you can use it in your case
create or alter procedure sp_goods (id varchar(60))
returns (
good varchar(50),
good_id integer)
as
begin
for select good_id, good from goods
where good_id in (select cast("Line" as numeric (18, 0))
from "Split_Line" (:id, ','))
into :good_id, :good
do suspend;
end
Supporting procedure to compile before Split_String
create or alter procedure "Pos"
( SUBSTR VARCHAR (100),
STR VARCHAR (16000))
returns ( "Result" INTEGER)
as
DECLARE VARIABLE SubStr2 VARCHAR(16256); /* 1 + SubStr-lenght + Str-length */
DECLARE VARIABLE Tmp VARCHAR(255);
BEGIN
IF (SubStr IS NULL OR Str IS NULL)
THEN BEGIN
"Result" = NULL;
suspend;
EXIT;
END
IF (SubStr = '' OR Str = '')
THEN BEGIN
"Result" = 0;
suspend;
EXIT;
END
SubStr2 = SubStr || '%';
Tmp = '';
"Result" = 1;
WHILE (Str NOT LIKE SubStr2 AND Str NOT LIKE Tmp)
DO BEGIN
SubStr2 = '_' || SubStr2;
Tmp = Tmp || '_';
"Result" = "Result" + 1;
END
IF (Str LIKE Tmp)
THEN "Result" = 0;
suspend;
END
And I have replaced my substr (from my user defined function library) to use the firebird substring in the Split_Line procedure.
Apologies for the quoted identifiers, always use Dialect 3. And the odd capitalisation was to support Crystal Reports which at that time would only work with uppercase procedures.
The other way to do it is to use Dynamic Queries.
create or alter procedure sp_goods (id varchar(60))
returns (
good varchar(50),
good_id integer)
as
declare lsql varchar (5000);
begin
lsql = 'select good_id, good from goods where good_id in (' || :id || ')';
for execute statement lsql
into :good_id, :good
do suspend;
end
Disadvantages
Normally, when a procedure is compiled, the queries are prepared at that time. So, execution is faster. With Dynamic Queries or Dynamic Sql, the query has to be prepared every time the procedure is executed.
Normally, when a procedure is compiled, the engine validates the table and fields etc. In this case the validation happens at execution time. So you have to be really careful how you construct your query.
Note - I havent had time to test it with a real table, but it compiles. (Its 3am, so I might check that tomorrow).
I wouldn't normally recommend this, but everything has a place.
In the following query I am using a stored procedure to create a table output_tbl_name from a source_tbl. The name of the output_tbl_name is timestamped with today's date.
DECLARE
creation_date STRING := to_varchar(current_date(), 'YYYYMMDD');
output_tbl_name STRING := concat('my_database.my_schema.', 'output_', :creation_date);
QUERY STRING;
BEGIN
QUERY:= REPLACE(
'create or replace table <output_tbl_name>(col1 varchar, col2 varchar) as
select * from source_tbl;'
,'<output_tbl_name>', :output_tbl_name); ;
EXECUTE IMMEDIATE :QUERY;
RETURN :QUERY;
END;
However, I would like to set a dynamic criteria for the data that is copied over. E.g., the source_tbl has a date column, and I want to only copy over records for dates > 6 months ago:
declare start_date date := add_months(current_date(), -6)
create or replace output_tbl_name as select * from source_tbl where date > <start_date>
How can I incorporate this into my above query? Placing it directly into my QUERY in my BEGIN statement isn't working. Thanks for your help!
create a source data table:
CREATE OR REPLACE TABLE tmp_table(col1 string);
DECLARE
creation_date STRING := to_varchar(current_date(), 'YYYYMMDD');
output_tbl_name STRING := concat('my_database.my_schema.', 'output_', :creation_date);
QUERY STRING;
source_tbl STRING := 'TMP_TABLE';
BEGIN
LET date_present := false;
SELECT true INTO :date_present FROM INFORMATION_SCHEMA.columns WHERE table_name = :source_tbl AND column_name = 'DATE';
if (date_present = true) then
QUERY := 'create or replace table <output_tbl_name>(col1 varchar, col2 varchar) as select * from source_tbl where date > <start_date>;';
ELSE
QUERY:= 'create or replace table <output_tbl_name>(col1 varchar, col2 varchar) as select * from source_tbl;';
END IF;
QUERY:= REPLACE( QUERY, '<output_tbl_name>', :output_tbl_name);
--EXECUTE IMMEDIATE :QUERY;
RETURN :QUERY;
END;
begin
let count := true;
if (count = true) then
return 'negative value';
elseif (count = 0) then
return 'zero';
else
return 'positive value';
end if;
end;
anonymous block
create or replace table my_database.my_schema.output_20220307(col1 varchar, col2 varchar) as select * from source_tbl;
put in a date column:
CREATE OR REPLACE TABLE tmp_table(col1 string, date timestamp);
anonymous block
create or replace table my_database.my_schema.output_20220307(col1 varchar, col2 varchar) as select * from source_tbl where date > <start_date>;
I am new to Pl Sql. I am trying to run procedure and getting these errors:
Encountered the symbol "Create" with begin case declare end exception exit for goto if loop mod null pragma raise return select update while with
<< continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall
merge pipe purge:
I have tried searching for what causes these errors and for examples similar to this, but results were not sufficient. And this is my script:
CREATE OR REPLACE PROCEDURE CommandScript IS
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE sf_tmp';
EXCEPTION
WHEN OTHERS THEN IF SQLCODE != -942
THEN RAISE;
END IF;
create table sf_tmp(smcard varchar2(17),p_line varchar2(1000));
INSERT INTO dec_tmp(DECSCNR,DECSCPSNR)
SELECT TRIM (SUBSTRB (qinputstring, INSTR (qinputstring, '|', 1, 2) + 1,11)) dec_nr,
decoders.decscpsnr FROM bgqueue, decoders WHERE qworktype = 10
AND decoders.decscpsnr > 0 AND decoders.decscnr =
TRIM (SUBSTRB (qinputstring,INSTR (qinputstring, '|', 1, 2) + 1,11))
AND LENGTH (TRIM (SUBSTRB (qinputstring,INSTR (qinputstring, '|', 1, 2) + 1,11))) = 11;
commit;
declare
CURSOR smcard_cursor IS
(select d.DECSCNR,d.DECSCPSNR from dec_tmp d);
CURSOR prod_cursor (v_pslink number ) IS
(select p.psdecscpsnrlink, c.CPCSIENTITLEMENTS
from csiprod c, prodsubs p
where p.psdecscpsnrlink = v_pslink
and c.CPIBSPRODUCTNR = p.psproductnr
and c.CPCONDITIONNR =1
and c.cpcsientitlements<>'NILDRA'
and p.psstatus = 'A' ) ;
m_decno varchar2(17) ;
v_decno varchar2(17) ;
prod_line VARCHAR2(1000) ;
prod_full VARCHAR2(1000) ;
comma_line VARCHAR2(1000) ;
prod_len number ;
prod_diff number ;
new_prodct varchar2(300) ;
L_Size NUMBER ;
new_size number ;
s_link number ;
space_con number ;
sw number ;
BEGIN
FOR smcard_record IN smcard_cursor LOOP
prod_line := '' ;
prod_full := '' ;
comma_line := '' ;
prod_len :=0 ;
prod_diff :=0 ;
L_Size :=0 ;
new_size := 0 ;
space_con := 0;
new_prodct := '' ;
sw := 0 ;
S_link := smcard_record.decscpsnr ;
v_decno:= substr(smcard_record.decscnr,1,10) ;
m_decno:= substr(smcard_record.decscnr,1,11) ;
FOR prod_record IN prod_cursor (s_link) LOOP
SW := 1 ;
prod_len := length(prod_record.CPCSIENTITLEMENTS) ;
prod_diff := mod(prod_len,6) ;
if prod_diff = 0 THEN
new_prodct := prod_record.CPCSIENTITLEMENTS ;
else
space_con :=prod_len+6-prod_diff ;
new_prodct := rpad(prod_record.CPCSIENTITLEMENTS, space_con,' ') ;
end if ;
prod_line := prod_line || new_prodct ;
end loop ;
if sw = 1 then
L_size := length(prod_line) ;
comma_line := comma_line || substr(prod_line,1,6);
for I in 1..L_size LOOP
IF MOD(I,6) = 0 THEN
comma_line := comma_line ||',' || substr(prod_line,(I+1),6) ;
END IF;
end loop ;
new_size := length(comma_line) - 1 ;
comma_line := substr(comma_line,1,new_size) ;
prod_FULL :='SOFULL'||','||'002000,'|| v_decno||',EGY,'||'EG,'||'NONE ,'||comma_line ;
insert into sf_tmp (smcard,p_line) values (m_decno,prod_full) ;
commit ;
end if ;
end loop ;
END;
END;
I beleive you don't need '/' at line 10.
You can't execute DDL in a procedure natively. Wrap it in an EXECUTE IMMEDIATE
create table sf_tmp(smcard varchar2(17),p_line varchar2(1000));
You don't end your begin statement, which mean your procedure sees
create procedure begin ... declare ... begin ... end ... end
You don't need a declare in compiled code so this should be:
create procedure ... begin ... end ... begin ... end
The second begin ... end being what you want to execute on compilation (i.e. the creating and dropping of your tables)
You can't reference non-existent tables in a procedure. Given that you're allowing for your table to not exist at the beginning you need to wrap this in an EXECUTE IMMEDIATE.
insert into sf_tmp (smcard,p_line) values (m_decno,prod_full) ;
Please start using the ANSI join syntax, rather than joining in your WHERE clause
Oracle recommends that you use the FROM clause OUTER JOIN syntax rather than the Oracle join operator. Outer join queries that use the Oracle join operator (+) are subject to the following rules and restrictions, which do not apply to the FROM clause OUTER JOIN syntax:
LISTAGG() should help you significantly.
A global temporary table should remove the need to perform DDL in your procedure at all.
Without investigating too hard, your entire procedure looks like it can be done in a single INSERT statement...
Lastly, it looks like you're generating partial SQL to be executed later. This can be a valid approach in very specific circumstances, but I'd seriously reconsider whether it is before continuing.
I'm trying to find out if String is "mnemonic type"...
My mnemonic type consists of letters from 'a' to 'z' and from 'A' to 'Z', digits from '0' to '9', and additionaly '_'.
I build code like below. It should result with True if given string match my mnemonic pattern otherwise False:
TRes := True;
for I := 0 to (AString.Length - 1) do
begin
if not ((('0' <= AString[I]) and (AString[I] <= '9'))
or (('a' <= AString[I]) and (AString[I] <= 'z'))
or (('A' <= AString[I]) and (AString[I] <= 'Z'))
or (AString[I] = '_')) then
TRes := False;
end;
This code always results with False.
I'm assuming that since you tagged the question XE5, and used zero-based indexing, that your strings are zero-based. But perhaps that assumptions was mistaken.
Your logic is fine, although it is rather hard to read. The code in the question is already doing what you intend. At least the if statement does indeed perform the test that you intend.
Let's just re-write your code to make it easier to understand. I'm going to lay it our differently, and use a local loop variable to represent each character:
for C in AString do
begin
if not (
(('0' <= C) and (C <= '9')) // C is in range 0..9
or (('a' <= C) and (C <= 'z')) // C is in range a..z
or (('A' <= C) and (C <= 'Z')) // C is in range A..Z
or (C = '_') // C is _
) then
TRes := False;
end;
When written like that I'm sure that you will agree that it performs the test that you intend.
To make the code easier to understand however, I would write an IsValidIdentifierChar function:
function IsValidIdentifierChar(C: Char): Boolean;
begin
Result := ((C >= '0') and (C <= '9'))
or ((C >= 'A') and (C <= 'Z'))
or ((C >= 'a') and (C <= 'z'))
or (C = '_');
end;
As #TLama says, you can write IsValidIdentifierChar more concisely using CharInSet:
function IsValidIdentifierChar(C: Char): Boolean;
begin
Result := CharInSet(C, ['0'..'9', 'a'..'z', 'A'..'Z', '_']);
end;
Then you can build your loop on top of this function:
TRes := True;
for C in AString do
if not IsValidIdentifierChar(C) do
begin
TRes := False;
break;
end;
String type is 1-based. dynamic Arrays are 0-based. Better use for ... in so you are safe for future Delphi's.
Testing for ranges of possible character values can be done more efficiently (and more conciece) is CharInSet.
function IsMnemonic( AString: string ): Boolean;
var
Ch: Char;
begin
for Ch in AString do
if not CharInSet( Ch, [ '_', '0'..'9', 'A'..'Z', 'a'..'z' ] ) then
Exit( False );
Result := True;
end;
i got this sp:
DROP TABLE IF EXISTS SplitValuesDump;
CREATE TABLE SplitValuesDump (
value VARCHAR(1000) NOT NULL PRIMARY KEY
);
DELIMITER $$
DROP PROCEDURE IF EXISTS `ChangeSitesRedirects`$$
CREATE PROCEDURE `ChangeSitesRedirects`(
prodimainAddress varchar(255),
subdomainMainAddress varchar(255)
)
SQL SECURITY INVOKER
BEGIN
DECLARE tdomain varchar(1000);
DECLARE tvalue varchar(1000);
DECLARE prepValue varchar(1000);
DECLARE subdomainFullAddress varchar(1000);
DECLARE totalDomain int;
DECLARE tclientid int;
DECLARE sitedone INT DEFAULT 0;
DECLARE splitdone INT DEFAULT 0;
DECLARE lastDomain varchar(1000);
DECLARE curlSites CURSOR FOR (SELECT domain,clientid from sites where redirectsubdomain = 'N');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET sitedone = 1;
set sitedone := 0;
OPEN curlSites;
Scan_Sites:WHILE (sitedone = 0) DO
IF sitedone = 1 THEN
BEGIN
LEAVE Scan_Sites;
END;
ELSE
BEGIN
DECLARE curlStringDump CURSOR FOR (SELECT `value` from SplitValuesDump);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET splitdone = 1;
FETCH curlSites INTO tdomain,tclientid;
CALL split_string(tdomain,';');
OPEN curlStringDump;
SET splitdone:=0;
ScanDump: WHILE (splitdone = 0) DO
IF splitdone = 1 THEN
BEGIN
LEAVE ScanDump;
END;
ELSE
BEGIN
FETCH curlStringDump INTO tvalue;
SET subdomainFullAddress:= subdomainMainAddress;
IF tvalue <> "" THEN
BEGIN
IF tvalue like prodimainAddress OR tvalue like subdomainMainAddress THEN
BEGIN
set totalDomain := totalDomain + 1;
IF tvalue like subdomainMainAddress THEN
BEGIN
SET subdomainFullAddress := tvalue;
END;
END IF;
END;
ELSE
BEGIN
set totalDomain := totalDomain + 1;
set lastDomain := tvalue;
END;
END IF;
END;
END IF;
END;
END IF;
END WHILE ScanDump;
CLOSE curlStringDump;
SET splitdone :=0;
SET prepValue:='N';
IF lastDomain = '' AND totalDomain = 2 THEN
BEGIN
set prepValue := subdomainFullAddress || CHAR(2) || prodimainAddress;
INSERT INTO sites_tmp SELECT * FROM sites where clientid = tclientid limit 1;
UPDATE sites_tmp SET redirectsubdomain = prepValue WHERE clientid = tclientid limit 1;
END;
ELSE
BEGIN
set prepValue := prodimainAddress || CHAR(2) || lastDomain || CHAR(1) ||subdomainFullAddress || CHAR(2) || lastDomain;
INSERT INTO sites_tmp SELECT * FROM sites where clientid = tclientid limit 1;
UPDATE sites_tmp SET redirectsubdomain = prepValue WHERE clientid = tclientid limit 1;
END;
END IF;
END;
END IF;
END WHILE Scan_Sites;
CLOSE curlSites;
SET sitedone :=0;
END$$
i try in the get few info from column data split his data and bring some data ion there.
for each recored on table sites
and then update table sites_tmp.
i got issue that i not know how i can debug at or make at faster?
what ur recommend here?
as well why its so slow???
and in the end its not passed the all the records?