I'm stuck on this block of statements and don't know how to program the output when the code runs to show the amount of the payment as $10.00 and the balance remaining in the same format. My code also prompts me twice for idpledge... I've got some markup in the code for topics I don't quite understand. Using Oracle 11g 2e and the book isn't very helpful. If there is a recommendation for beginner books or resources I am listening (reading). Code is below:
SET SERVEROUTPUT ON;
DECLARE
pay_num NUMBER(2) := 0; /*initialize to 0 */
loop_count NUMBER(2) := 12; /*intialize to max number of months */
pay_amt NUMBER(8,2);
pledge_bal NUMBER(8,2);
v_pledgeamt NUMBER(8,2);
start_date DATE := '04-OCT-2012';
due_date DATE;
v_due_date VARCHAR2(15);
BEGIN
SELECT pledgeamt INTO v_pledgeamt
FROM DD_PLEDGE
WHERE idpledge=&idpledge;
pay_amt := (v_pledgeamt / loop_count);
due_date := start_date;
pledge_bal := (v_pledgeamt - pay_amt);
FOR i IN 1..loop_count LOOP
pay_num := pay_num + 1;
v_due_date := TO_CHAR(due_date, 'MM-DD-YYYY');
due_date := add_months(due_date, 1);
pledge_bal := (pledge_bal - pay_amt);
DBMS_OUTPUT.PUT_LINE (
'Payment Num: ' || pay_num
|| ' ' || 'Due Date: ' || v_due_date
|| ' ' || 'Amount Due: ' || pay_amt
|| ' ' || 'Balance: ' || TO_CHAR(pledge_bal, '$')); /* how to format with $*/
END LOOP;
END;
As mentioned at Docs you can use the to_char with a proper formatter. In your case it would be to_char(pledge_bal, '$9,999.99')
Using the format as '$9,999.99' fulfills the following objectives :
Returns a comma in the specified position. You can specify multiple commas in a number format model.
Returns a decimal point, which is a period (.) in the specified position.
Returns value with a leading dollar sign.
If required you can check for more parameters at the link mentioned.
Related
I am working on creating one view in SAP HANA.
I have column A, Data type for A is NVARCHAR.
Values in A are something like below. I need to use only last 5 digits and convert it into decimal.
A
000000000000000000000000000EF80A
000000000000000000000000000EF812
000000000000000000000000000EF80E
000000000000000000000000000EF809
000000000000000000000000000EF80B
000000000000000000000000000EF80C
000000000000000000000000000EF80D
I made use of function
Select HEXTOBIN(0xEF80A) from dummy;
This gave me required result.
However 0x in above query is notation to mark number (EF80A) as hexadecimal.
Whenever I have to fetch 5 last digit dynamically, I am not able to assign 0x notation.
I tried following:
1) substr last 5 digits of A and concat it with 0x... This did not work, as '0x'is considered as string while it is just notation.
select distinct '0x' || right(A,5 ) from dummy;
Can someone help as to how I give 0x with last 5 char of column A to mark it hexadecimal?
Are there any direct function available for this conversion without user defined function?
The 0x... notation for hexadecimal numbers and the X'...' for strings are only valid for typed literals.
E.g. 0xEF80A explicitly types the literal a number given in hexadecimal notation. Internally, the number is of course dealt with as if you would've given an integer.
In order to be able to apply this to existing strings, a hex-string-to-number conversion function is required and SAP HANA doesn't come with one on board.
I've posted an example implementation for such a function here https://archive.sap.com/discussions/thread/3652555
To make it easy, here's it again:
drop function hexstr2int;
CREATE FUNCTION hexstr2int (IN i_hex VARCHAR(2000))
RETURNS o_result BIGINT
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
READS SQL DATA
AS
BEGIN
DECLARE pos INTEGER := 1;
DECLARE hex_len INTEGER;
DECLARE current_digit VARCHAR(1);
DECLARE current_val INTEGER;
DECLARE result BIGINT := 0;
DECLARE tmphex VARCHAR(2000);
DECLARE hexstr2int CONDITION FOR SQL_ERROR_CODE 10001;
DECLARE EXIT HANDLER FOR hexstr2int RESIGNAL;
-- some sanitation
tmphex := UPPER(:i_hex);
hex_len := LENGTH(:tmphex);
WHILE :pos <= :hex_len DO
result := :result * 16;
current_digit := SUBSTR(:tmphex, :pos, 1);
-- format checking
IF NOT ((:current_digit >= 'A' and :current_digit <= 'F') or
(:current_digit >= '0' and :current_digit <= '9')) THEN
SIGNAL hexstr2int SET MESSAGE_TEXT =
'Invalid hex cipher: ' || :current_digit || ' at position ' || :pos;
END IF;
current_val := MOD(to_number(to_binary(:current_digit)),30);
IF :current_val >= 11 THEN
result := :result + :current_val - 1;
ELSE
result := :result + :current_val;
END IF;
pos := :pos + 1;
END WHILE;
o_result := :result;
END;
I have a stored procedure which is driving me nuts. I know it's a pretty simple thing, but I think I am not able to figure it out.
I am getting the error
"PLS-00382: expression is of wrong type"
in below line:
-- Write the result into Log
v_LogText := 'Summary Elapsed Time: ' || TO_CHAR(floor((cast(SYSTIMESTAMP as date) - Cast(v_StartTime as date)) * 86400)) || 'sec Batchsize ' || TO_CHAR (v_BatchSize);
Std.Log (v_WorkerName,'001','CAS', '0', 'en', ' 00000000', v_LogText );
Declarations:
v_LogText NVARCHAR2(2000);
v_BatchSize NUMBER(10,0) := iv_BatchSize; [ and iv_BatchSize is passed in the procedure as a paramenet like "iv_BatchSize IN NUMBER DEFAULT NULL"]
v_StartTime DATE := SYSDATE;
I already tried to change SYSTIMESTAMP to SYSDATE but no luck.
Assuming the amount of information provided, please check below way to do it. Hope this works for you.
declare
v_LogText NVARCHAR2(2000);
v_BatchSize NUMBER(10,0) := 76363;
v_StartTime DATE := SYSDATE;
a varchar2(100);
begin
select TO_CHAR(floor((cast(SYSTIMESTAMP as date) - Cast(v_StartTime -1 as date)) * 86400))
into a
from dual;
v_LogText := 'Summary Elapsed Time: ' || a || 'sec Batchsize ' || TO_CHAR (v_BatchSize);
dbms_output.put_line(v_LogText);
end;
How do I make arrays in PL / SQL?
I have a string that I want to split on spaces and then loop through them all.
Declare your array like this:
"your array" apex_application_global.vc_arr2;
"your array" := APEX_UTIL.STRING_TO_TABLE("your string",' ');
FOR i IN 1.. "your array".COUNT LOOP
"Your string" := "Your string"|| "your array"(i);
END LOOP;
and there you have it
And this is the ultimate and universal solution without using any packages, just oracle SQL. See a full featured solution (including a pipelining function) over here: http://www.armbruster-it.org/index.php/12-it/pl-sql/20-string-tokenizer-with-oracle-pl-sql
declare
cursor c_tokenizer(ci_string in varchar2, ci_delimiter in varchar2) is
SELECT regexp_substr(str, '[^' || ci_delimiter || ']+', 1, LEVEL) AS splitted_element,
LEVEL AS element_no
FROM (SELECT rownum AS id, ci_string str FROM dual)
CONNECT BY instr(str, ci_delimiter, 1, LEVEL - 1) > 0
AND id = PRIOR id
AND PRIOR dbms_random.value IS NOT null;
l_string varchar2(100) := 'Hello World, I like PL/SQL';
l_delimiter varchar2(1) := ' ';
begin
-- extract each word of the string above (delimited by blank)
for c1 in c_tokenizer(l_string, l_delimiter) loop
dbms_output.put_line(c1.splitted_element);
end loop;
end;
The Result is:
Hello
World,
I
like
PL/SQL
-- File: PLh10.sql
-- Author: John Tunisi
-- ----------------------------------
SET SERVEROUTPUT ON
SET VERIFY OFF
-- ----------------------------------
ACCEPT traineeID NUMBER PROMPT 'Enter a trainee ID: '
ACCEPT increment NUMBER PROMPT 'Enter an increment for his trainers: '
DECLARE
sr sailors%ROWTYPE;
CURSOR tCursor IS
SELECT S.sid, S.sname, S.rating, S.age, S.trainee
FROM sailors S, sailors R
WHERE R.sid = '&traineeID' AND
S.trainee = R.sid;
BEGIN
OPEN tCursor;
LOOP
-- Fetch the qualifying rows one by one
FETCH tCursor INTO sr;
-- Print the sailor' old record
DBMS_OTPUT.PUT_LINE ('+++++ old row: '||sr.sid||' '
||sr.sname||sr.rating||' '||sr.age||' '||sr.trainee);
-- Increment the trainers' rating
sr.rating := sr.rating + &increment;
UPDATE sailors
SET rating = sr.rating
WHERE sailors.sid = sr.sid;
-- Print the sailor' new record
DBMS_OUTPUT.PUT_LINE ('+++++ new row: '||sr.sid||' '
||sr.sname||sr.rating||' '||sr.age||' '||sr.trainee);
END LOOP;
IF tCursor%ROWCOUNT = 0 /*test whether the trainee has no trainers*/
DBMS_OUTPUT.PUT_LINE ('+++++ '||sr.sid||' is either not a sailor,'
||' or has no trainer');
ELSE
DBMS_OUTPUT.PUT_LINE ('+++++ DB has been updated');
END IF;
CLOSE tCursor;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('+++++'||SQLCODE||'...'||SQLERRM);
END;
/
-- Let's see what happened to the database
SELECT *
FROM sailors S
WHERE S.trainee = '&traineeID';
UNDEFINE traineeID
UNDEFINE increment
Okay, so I need to increment trainers based on a trainee. I think most of it is correct, but I am getting an error on the line below " DBMS_OUTPUT.PUT_LINE ('+++++ '||sr.sid||' is either not a sailor,'". I am not sure what is supposed to go here, as this is my first time writing PL/SQL.
Try this:
SET SERVEROUTPUT ON
SET VERIFY OFF
-- ----------------------------------
ACCEPT traineeID NUMBER PROMPT 'Enter a trainee ID: '
ACCEPT increment NUMBER PROMPT 'Enter an increment for his trainers: '
DECLARE
sr sailors%ROWTYPE;
srNew sailors%ROWTYPE;
nRecords_updated NUMBER := 0;
CURSOR tCursor IS
SELECT S.sid, S.sname, S.rating, S.age, S.trainee
FROM sailors S, sailors R
WHERE R.sid = '&traineeID' AND
S.trainee = R.sid;
BEGIN
OPEN tCursor;
LOOP
-- Fetch the qualifying rows one by one
FETCH tCursor INTO sr;
EXIT WHEN tCursor%NOTFOUND; -- ADDED
-- Print the sailor' old record
DBMS_OUTPUT.PUT_LINE ('+++++ old row: ' || sr.sid || ' ' ||
sr.sname || sr.rating || ' ' || sr.age ||
' ' || sr.trainee);
-- Increment the trainers' rating
sr.rating := sr.rating + &increment;
UPDATE sailors
SET rating = sr.rating
WHERE sailors.sid = sr.sid;
nRecords_updated := nRecords_updated + SQL%ROWCOUNT; -- ADDED
-- Obtain the updated record -- ADDED
SELECT s.* -- ADDED
INTO srNew -- ADDED
FROM SAILORS s -- ADDED
WHERE s.SID = sr.SID; -- ADDED
-- Print the sailor' new record
DBMS_OUTPUT.PUT_LINE ('+++++ new row: ' || srNew.sid || ' ' || -- CHANGED
srNew.sname || srNew.rating || ' ' || -- CHANGED
srNew.age || ' ' || srNew.trainee); -- CHANGED
END LOOP;
IF nRecords_updated = 0 /*test whether the trainee has no trainers*/ -- CHANGED
DBMS_OUTPUT.PUT_LINE ('+++++ ' || sr.sid || ' is either not a sailor,' ||
' or has no trainer');
ELSE
DBMS_OUTPUT.PUT_LINE ('+++++ DB has been updated');
END IF;
CLOSE tCursor;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('+++++'||SQLCODE||'...'||SQLERRM);
END;
/
I included comments (either ADDED or CHANGED) on the lines I altered or added. It's tough to say whether this will work or not as I don't have access to your data but it might be a step in the right direction.
Share and enjoy.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I'm using PL/SQL developer to créate this trigger, I read somewhere that it could be a CR-LF missinterpretation by Oracle, but it is the first time this occurs. Below the code is the Error log:
create or replace trigger Terreno_nomenc
before update of circ_prov,sector_prov,cod_div_prov,nro_div_prov,nro_parc_prov on adminmo.terreno
for each row
declare
circ integer:= 0;
sector integer:= 0;
cod_div integer:= 0;
nro_div integer:= 0;
nro_par integer:= 0;
nueva_nomenc varchar2(18) := ' ';
vieja_nomenc varchar2(18) := ' ';
dominio integer:= 0;
begin
vieja_nomenc:= :old.nomenc;
if (:new.circ_prov <> :old.circ_prov) then {
circ := :new.circ_prov;
}
else {
circ := :old.circ_prov;
}
end if;
if(:new.sector_prov <> :old.sector_prov) then {
sector := :new.sector_prov;
}
else {
sector := :old.sector_prov;
}
end if;
if(:new.cod_div_prov <> :old.cod_div_prov) then {
cod_div := :new.cod_div_prov;
}
else{
cod_div := :old.cod_div_prov;
}
end if;
if(:new.nro_div_prov <> :old.nro_div_prov) then {
nro_div := :new.nro_div_prov;
}
else{
nro_div := :old.nro_div_prov;
}
end if;
if(:new.nro_parc_prov <> :old.nro_parc_prov) then {
nro_par := :new.nro_parc_prov;
}
else{
nro_par := :old.nro_parc_prov;
}
end if;
if(circ > 0 and sector > 0 and cod_div > 0 and nro_div > 0) {
nueva_nomenc := to_char(circ,'999') || '-' || to_char(sector,'99') || '-' || to_char(cod_div,'99') || '-' || to_char(nro_div,'9999') || '-' || to_char(nro_par, '999');
select t.refnro into dominio
from geoimax.comodoro_ejido_dom_ref t
where t.reftex = vieja_nomenc;
update terreno set nomenc = nueva_nomenc where terreno.subsistema = :new.subsistema and terreno.partida = :new.partida;
update geoimax.Comodoro_Ejido_Dom_Ref c set c.reftex = nueva_nomenc where c.refnro = dominio;
}
end if;
end Terreno_nomenc;
Error: PLS-00103: Encountered the symbol "{" when expecting one of the following:
( begin case declare exit for goto if loop mod null pragma
raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
The symbol "begin was inserted before "{" to continue.
Line: 19
Text: if (:new.circ_prov <> :old.circ_prov) then {
Error: PLS-00103: Encountered the symbol "}" when expecting one of the following:
( begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<an identifier> <a double-quoted delimited-identifier>
<a bind variable> << continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall
merge pipe purge
Line: 21
Text: }
You don't use curly brackets in PL/SQL. None of the { or } characters in your code are needed and all of them are syntax errors. You'll need to remove all those characters.
Once you do that, you may still get syntax errors (since you didn't post your table definitions, we have no way to try to fix the trigger and verify that it compiles on our system). But they'll at least be different errors.
On closer inspection, you also appear to have an UPDATE statement in the trigger that is trying to update rows in the table that the row-level trigger is defined on. The trigger is trying to update terreno and is defined on a table terreno (unless you have two tables with the same name in different schemas and you are being very tricky with name resolution). That's going to throw a mutating table error when you try to run it. Are you actually trying to modify the current row that is being updated? Or are you trying to update other rows in the table? If the latter, that strongly implies that the data model is incorrect because that implies that data in one row depends on data in other rows of the same table which violates basic normalization.
If you are merely trying to modify data in the current row, don't use an UPDATE. Simply modify the :new pseudorecord.
:new.nomenc := nueva_nomenc;
Couple of errors:
{} curly braces should be removed.
THEN missed out in one of the IF statements.
CREATE OR replace TRIGGER terreno_nomenc
BEFORE UPDATE OF circ_prov, sector_prov, cod_div_prov, nro_div_prov,
nro_parc_prov ON adminmo.terreno
FOR EACH ROW
DECLARE
circ INTEGER := 0;
sector INTEGER := 0;
cod_div INTEGER := 0;
nro_div INTEGER := 0;
nro_par INTEGER := 0;
nueva_nomenc VARCHAR2 ( 18 ) := ' ';
vieja_nomenc VARCHAR2 ( 18 ) := ' ';
dominio INTEGER := 0;
BEGIN
vieja_nomenc := :OLD.nomenc;
IF ( :NEW.circ_prov <> :OLD.circ_prov ) THEN
circ := :NEW.circ_prov;
ELSE
circ := :OLD.circ_prov;
END IF;
IF ( :NEW.sector_prov <> :OLD.sector_prov ) THEN
sector := :NEW.sector_prov;
ELSE
sector := :OLD.sector_prov;
END IF;
IF ( :NEW.cod_div_prov <> :OLD.cod_div_prov ) THEN
cod_div := :NEW.cod_div_prov;
ELSE
cod_div := :OLD.cod_div_prov;
END IF;
IF ( :NEW.nro_div_prov <> :OLD.nro_div_prov ) THEN
nro_div := :NEW.nro_div_prov;
ELSE
nro_div := :OLD.nro_div_prov;
END IF;
IF ( :NEW.nro_parc_prov <> :OLD.nro_parc_prov ) THEN
nro_par := :NEW.nro_parc_prov;
ELSE
nro_par := :OLD.nro_parc_prov;
END IF;
IF ( circ > 0
AND sector > 0
AND cod_div > 0
AND nro_div > 0 ) THEN
nueva_nomenc := To_char (circ, '999')
|| '-'
|| To_char (sector, '99')
|| '-'
|| To_char (cod_div, '99')
|| '-'
|| To_char (nro_div, '9999')
|| '-'
|| To_char (nro_par, '999');
SELECT T.refnro
INTO dominio
FROM geoimax.comodoro_ejido_dom_ref T
WHERE T.reftex = vieja_nomenc;
UPDATE terreno
SET nomenc = nueva_nomenc
WHERE terreno.subsistema = :NEW.subsistema
AND terreno.partida = :NEW.partida;
UPDATE geoimax.comodoro_ejido_dom_ref C
SET C.reftex = nueva_nomenc
WHERE C.refnro = dominio;
END IF;
END terreno_nomenc;
/