Oracle11G Sql: Computing mathematical operations using function? - oracle11g

I am using Oracle 11G sql and I want to calculate the Total_price which which means quantity*unit_price. How to do that by creating function for the columun
Total_price?
Because Experts are there and they can help me.
here is my table attributes with their corresponding data
Table: ITEM
item_id item_name quantity unit_price Total_price
-------------------------------------------------------------
1001 soap 5 $10
1002 Omo 2 $15
1003 Perfume 1 $52
1004 Socks 3 $7
1005 Tooth Brush 2 $5
I tried this:
CREATE OR REPLACE FUNCTION total_ammount_fn
RETURN number (10,2);
IS
Total_amount number(10,2);
BEGIN
SELECT Quantity, Rate_per_unit, Total_amount
FROM purchase;
Total_amount=Quantity*Rate_per_unit;
RETURN Total_amount;
END;
/
finally:
Warning: Function is created with compilation errors.

As you are using 11g will suggest that you declare Total Price as a Virtual Column in your table ITEM. You can use the below syntax for column
Total_Price NUMBER(10,2) GENERATED ALWAYS AS (quantity*unit_price)
You can get more details of the Virtual Functions here
If you want to do it with a PL/SQL construct, then suggest that you use a procedure, it should be like :
CREATE OR REPLACE procedure total_ammount_p
IS
Begin
Update item set total_price = unit_price*quantity;
commit;
END;
/
Of the two, it will be better to use Virtual Column based approach
Hope is Helps
Vishad

Related

PLSQL Return Sequence.currval When Sequence Name Is Built Using Substitution Strings

I would like to use the same application in different instances so I need to specify the workspace and sequence ID.
Example query
BEGIN
INSERT INTO STEP (STEP_CHART_TITLE)
VALUES ('Action', 'Action');
RETURN '"'||:v_workspace||'"."'||:v_seqid||'".currval';
END;
If I use:
"FREEADMIN"."ISEQ$$_111997".currval;
in the return statement it works fine.
If I use the substitution strings, it will build the string correctly, but won't return the sequence number.
Is there a way to get the sequence number?
Thanks
"PL/SQL" as Oracle's procedural extension to SQL? Asking because I don't quite understand what "workspace" represents (we call it a "user" or a "schema" or even "owner" in Oracle).
If so, then you can't fetch current value unless you first fetch next sequence value (you didn't post whole code you use so I'm not sure whether you did that or not; also, insert statement is wrong - you're inserting 2 values into a single column).
SQL> select seq.currval from dual;
select seq.currval from dual
*
ERROR at line 1:
ORA-08002: sequence SEQ.CURRVAL is not yet defined in this session
SQL> select seq.nextval from dual;
NEXTVAL
----------
6
SQL> select seq.currval from dual;
CURRVAL
----------
6
SQL>
Therefore, the whole code might look like this - you'd use dynamic SQL. As this is SQL*Plus, I'm using substitution variables; you'd use bind variables (i.e. :v_workspace instead of '&v_workspace') (if that's what you're doing). This code just displays the value - you'd return it.
SQL> create table step (id number, step_chart_title varchar2(10));
Table created.
SQL> declare
2 l_str varchar2(200);
3 l_id number;
4 begin
5 l_str := 'select ' || '&v_workspace' ||'.'|| '&v_seqid' ||'.nextval from dual';
6 execute immediate l_str into l_id;
7
8 insert into step (id, step_chart_title) values (l_id, 'Action');
9
10 dbms_output.put_line(l_id); --> L_ID now contains CURRVAL
11 end;
12 /
Enter value for v_workspace: scott
Enter value for v_seqid: seq
8 --> here it is
PL/SQL procedure successfully completed.
SQL>

oracle 11g application express interface virtual column that calculates total amount of sales

Im currently working on my interface project by editing a certain page item of a form in oracle 11g application express. Im in confusion that one of the column is derived from another column in the table, does not work properly when i tried to register a new data through the interface. the column cannot calculate the derived data just like how it works in the oracle sql developer. i set the column as follows:
Im clueless, that should i display the column as hidden, or it has something to do with the source settings that needs PL/SQL expression to calculate the values of quantity, and cost_perunit column for total_amount values automatically. I have searched the web for the solution, but cant find a solution and a related issue to this.
this command was uploaded in a text .txt format into the application express
CREATE TABLE PAYMENT(
PAY_ID NUMBER(25)NOT NULL,
PAY_DATE DATE,
PAY_METHOD VARCHAR2(50 char),
SPARE_TYPE VARCHAR2(50 char),
QUANTITY NUMBER(12),
COST_PERUNIT NUMBER(6,2),
TOTAL_AMOUNT as (quantity*cost_perunit),
CONSTRAINT PAY_PK PRIMARY KEY(PAY_ID)
);
CREATE SEQUENCE pay_id_seq START WITH 400;
Im referring to the TOTAL_AMOUNT as (quantity*cost_perunit) column that returns error when i try to create a new data through the form. what should i change in the page edit settings, so it will work as it supposed to be.
You have two choices create a table without virtual column calculate total amount at run time
e.g select a.*,(quantity*cost_perunit) total_amount from payment a;
or create table with virtual column with keyword virtual
CREATE TABLE PAYMENT(
PAY_ID NUMBER(25)NOT NULL,
PAY_DATE DATE,
PAY_METHOD VARCHAR2(50 char),
SPARE_TYPE VARCHAR2(50 char),
QUANTITY NUMBER(12),
COST_PERUNIT NUMBER(6,2),
TOTAL_AMOUNT as (quantity*cost_perunit) VIRTUAL,
CONSTRAINT PAY_PK PRIMARY KEY(PAY_ID));
#ddl payment
DBMS_METADATA.GET_DDL(OBJECT_TYPE,OBJECT_NAME,OWNER)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE TABLE "SCOTT"."PAYMENT"
( "PAY_ID" NUMBER(25,0) NOT NULL ENABLE,
"PAY_DATE" DATE,
"PAY_METHOD" VARCHAR2(50 CHAR),
"SPARE_TYPE" VARCHAR2(50 CHAR),
"QUANTITY" NUMBER(12,0),
"COST_PERUNIT" NUMBER(6,2),
"TOTAL_AMOUNT" NUMBER GENERATED ALWAYS AS ("QUANTITY"*"COST_PERUNIT") VIRTUAL ,
CONSTRAINT "PAY_PK" PRIMARY KEY ("PAY_ID")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
TABLESPACE "EXAMPLE" ENABLE
) SEGMENT CREATION DEFERRED
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
TABLESPACE "EXAMPLE" ;
SQL> insert into payment (pay_id,pay_date,pay_method,spare_type,quantity,cost_perunit)
2 values
3 (&pid,&pdt,&pmethod,&spare,&qty,&cpu);
Enter value for pid: 101
Enter value for pdt: sysdate
Enter value for pmethod: 'CASH'
Enter value for spare: 'CREDIT CARD'
Enter value for qty: 12
Enter value for cpu: 1.9
1 row created.
Elapsed: 00:00:00.10
SQL> /
Enter value for pid: 102
Enter value for pdt: sysdate-1
Enter value for pmethod: 'DEBIT CARD'
Enter value for spare: 'CREDIT CARD'
Enter value for qty: 21
Enter value for cpu: 2.99
1 row created.
Elapsed: 00:00:00.00
SQL> commit;
Commit complete.
SQL> select * from payment;
PAY_ID PAY_DATE PAY_METHOD SPARE_TYPE QUANTITY COST_PERUNIT TOTAL_AMOUNT
---------- ------------------- -------------------------------------------------- -------------------------------------------------- ---------- ------------ ------------
101 2020-06-25 14:06:46 CASH CREDIT CARD 12 1.9 22.8
102 2020-06-24 14:07:29 DEBIT CARD CREDIT CARD 21 2.99 62.79
SQL>
Edit:I have no idea about apex but if you decide to create the table without virtual column you can add label box or non editable text box item and use formula to display calculation for apex forms run time

How to create trigger based on time period it has to do sum function

I want to create a trigger in oracle 11g - every 5 minutes it has to sum the values of price column in order table. How would i ?
The correct way to do this would be to have a materialized view which calculates the total.
create table t23 (id number primary key , qty number);
create materialized view log on t23;
create materialized view t23_total
refresh force
start with sysdate + 5/(60*24)
next sysdate + 5/(60*24)
as
select sum(qty) as total_qty
from t23
/
This is the most efficient way to main a total. This kicks off a refresh every five minutes. If you wanted to maintain the total in real time you could just use
create materialized view t23_total
refresh on commit
as
select sum(qty) as total_qty
from t23
/
You may create a scheduler job to run every 5 minutes.
declare
v_anon_block varchar2(500) :=
q'{begin
insert into mylog(log_date,total_price) select SYSDATE, SUM(price)
from order;
commit;
end;}';
begin
dbms_scheduler.create_job (
job_name => 'SUM_PRICE_JOB',
job_type => 'PLSQL_BLOCK',
job_action => v_anon_block,
start_date => SYSDATE,
repeat_interval => 'FREQ=MINUTELY;INTERVAL=5;',
enabled => TRUE,
comments => '5 minute Refresh');
end;
/
Why do you want to work with "old" data? I mean, what's the purpose in calculating that value every 5 minutes? Have it available in time, live, per request. Create a view or a function that does that, such as
create or replace view v_sum_price as
select sum(price)
from orders_table;
or
create or replace function f_sum_price
return number
as
retval number;
begin
select sum(price)
into retval
from orders_table;
return retval;
end;
Both of these most probably lack some additional info (order ID? Item ID? Something else?). Furthermore, I can't see a purpose in summing price value in orders table. How do you use it? For example, for a restaurant: ORDERS table contains the following prices:
ITEM PRICE QUANTITY
Coke 1.5 2
Burger 4.0 2
Wine 2.3 1
Salad 0.8 1
and now you know that sum of the PRICE column equals 8.6. What useful information does it contain? Absolutely none (or I can't see it).
Maybe it would help if you described what problem you're trying to solve.

pl /sql procedure execution giving an error

My stored proc is defined as
create or replace procedure TEST(
name IN table1.col_name%type,
price IN table1.col_price%type
)
is
begin
update table1 t set t.name =name where t.price = price;
commit;
end TEST;
I am trying to execute it as
exec TEST(name => 'John', price => 1000);
However, it gives invalid SQL error. What am i missing here?
Your input parameter %type statements claim the column names are col_name and col_price. But that is not how you refer to them in your stored procedure (name and price).
Bad things can happen when you name variables after column names. AskTom recommends a limited convention of variable naming conventions:
local variables start with L_
parameters start with P_
global package variables start with G_
That link has a good general discussion on PL/SQL naming conventions. I personally just use V_ for most variables (aside from indexes and other obvious things), but that's just me.
Lastly, the col_ in the column names seem redundant; simply use name and price as column names.
So, that said, I think this does what you want:
create table table1 (
name varchar2(30),
price number
);
create or replace procedure TEST(
p_name IN table1.name%type,
p_price IN table1.price%type
)
is
begin
update table1
set name = p_name
where price = p_price;
commit;
end TEST;
/
insert into table1 values ('John', 500);
commit;
select * from table1;
exec TEST(p_name => 'Bob', p_price => 500);
select * from table1;
-- Clean up test artifacts
drop procedure test;
drop table table1;
Giving the output:
table TABLE1 created.
PROCEDURE TEST compiled
1 rows inserted.
committed.
NAME PRICE
------------------------------ ----------
John 500
anonymous block completed
NAME PRICE
------------------------------ ----------
Bob 500
procedure TEST dropped.
table TABLE1 dropped.
I really don't understand the variable prefixing approach. Oracle don't do it with their own API's, and it would be extraordinarily irritating if they did. It always seems like a workaround, rather than a fix.
For me the fix is to namespace the variables with the procedure name. It keeps the argument names "clean" and makes your code 100% proof against capture:
create or replace procedure TEST(
name IN table1.col_name%type,
price IN table1.col_price%type)
is
begin
update table1 t
set name = test.name
where t.price = price;
commit;
end TEST;
Lots more info on capture here.

Get two records from PLSQL cursor

My question is short. I create a cursor to get some values from my table. I want to get the current record of cursor (the fetched record) and the next record from the cursor without fetching it, because I want to make a calculation over the current record and the next record. In traditional programming it's a simple operation; you can do it with a for index by increasing it by 1.
Do you have any suggestions?
I want to make a calculation over the
current record and the next record.
Presuming you are using Oracle, this can be done quite simply in SQL using analtyical functions, specifically the lead() function. This retrieves a column's value from the next nth record (default n=1).
SQL> select empno
2 , sal as this_sal
3 , lead(sal) over (order by empno) as next_sal
4 from emp
5 order by empno
6 /
EMPNO THIS_SAL NEXT_SAL
---------- ---------- ----------
7369 800 1600
7499 1600 1250
7521 1250 2975
7566 2975 1250
7654 1250 2850
7698 2850 2450
....
This query can be using in a cursor or any other mechanism for retrieving records.
I'm not sure you can do that without moving the cursor, but you should be able to accomplish the same goal like this (psuedocode):
open cursor;
fetch cursor to rec1;
if cursor%found then
loop
fetch cursor to rec2;
exit when cursor%notfound;
perform calculations with rec1 and rec2;
rec1 := rec2;
end loop;
end if;
To answer you specific question, you could use BULK COLLECT and its limit clause into a collection (table) variable.
DECLARE
CURSOR my_cursor IS
[YOUR SQL HERE];
TYPE t_my_type IS TABLE OF my_cursor%ROWTYPE INDEX BY BINARY_INTEGER;
v_my_var t_my_type;
BEGIN
FETCH my_cursor BULK COLLECT INTO v_my_var LIMIT 2;
dbms_output.put_line('My first value: ' || v_my_var(1).some_column);
dbms_output.put_line('My second value: ' || v_my_var(2).some_column);
END;
The limit clause will cause only the first two records to be fetched and stored. The first record will have an index of 1 and the second will be 2.
You can compare two variables by saving one into local and then compare it with cursor value for example
declare
l_local1 table_name%type := null;
begin
for c1 in (select
*
from
table_name
where some clause)
loop
-- do comparation
if l_local1 is not null and c1.field_value is not null then
-- do something to compare
.
.
.
-- empty local1 variable
l_local1 := null;
end if;
-- get the value of loop in local variable
l_local1 := c1.field_value;
end loop;
end;

Resources