Oracle SQL to display results from dividing one variable with another - oracle

I need to calculate the YTD weekly average for the GROSS_AMOUNT
In the below script, the first part of the code gets the number of weeks. The second part of the code gets the YTD sum for that same time period
How do I write the SQL so I can retrieve the actual value of YtdTotal/TotalWeeks?
SELECT YtdTotal/TotalWeeks FROM DUAL; does not work
-- STORES NUMBER OF WEEKS SINCE BEGINING OF YEAR INTO THE VARIABLE, TotalWeeks
DECLARE
TotalWeeks NUMBER;
BEGIN
SELECT to_number(to_char(sysdate, 'WW')) - to_number(to_char(trunc(sysdate, 'year'),'WW'))
INTO TotalWeeks
FROM DUAL
-- (retrieves number of weeks since beginning of year)
END
-- STORES THE SUM OF GROSS)AMOUNT FOR THE WEEKS CALCULATED ABOVE - INTO THE
DECLARE
VARIABLE, YtdTotal
BEGIN
SELECT SUM(GROSS_AMOUNT)
INTO YtdTotal
FROM PARENTS
WHERE process_date BETWEEN
(next_day(TRUNC(sysdate, 'year'),'SUN'))
AND
(next_day(TRUNC(sysdate),'SAT')-7);
END;

Don't use two separate anonymous PL/SQL blocks - combine them into one!
If you want to return the result, then - instead of an anonymous PL/SQL block - create a function.
CREATE OR REPLACE FUNCTION f_test
return NUMBER
IS
totalweeks NUMBER;
ytdtotal NUMBER;
result NUMBER;
BEGIN
-- STORES NUMBER OF WEEKS SINCE BEGINING OF YEAR INTO THE VARIABLE, TotalWeeks
SELECT TO_NUMBER (TO_CHAR (SYSDATE, 'WW'))
- TO_NUMBER (TO_CHAR (TRUNC (SYSDATE, 'year'), 'WW'))
INTO totalweeks
FROM DUAL;
-- (retrieves number of weeks since beginning of year)
-- STORES THE SUM OF GROSS)AMOUNT FOR THE WEEKS CALCULATED ABOVE - INTO THE
SELECT SUM (gross_amount)
INTO ytdtotal
FROM parents
WHERE process_date BETWEEN (NEXT_DAY (TRUNC (SYSDATE, 'year'), 'SUN'))
AND (NEXT_DAY (TRUNC (SYSDATE), 'SAT') - 7);
-- the final result
result := ytdtogal / totalweeks;
RETURN result;
END;
/
Use it as
select f_test from dual;

Related

Using a date variable in a query to fetch records based on a given date in oracle

I need to write a function in oracle plsql that with take a date as an input and return records from a table for that particular day. If no date is given then fetch the records for current day.
Note that the column (purchase_date) is a timestamp(6) type not null column and has an index on it so I would not like to use trunc() function on the column.
Example value present in purchase_date column is --> 01-DEC-21 06.14.06.388855001 AM
create or replace FUNCTION getRecordsForDate(
input_date DATE DEFAULT SYSDATE
) RETURN sys_refcursor IS
data_out SYS_REFCURSOR;
BEGIN
OPEN data_out FOR
SELECT
p.product_name,
p.product_type,
p.purchased_by
FROM
product_details p
WHERE
AND p.purchase_date BETWEEN TO_DATE(input_date, 'DD-MON-YY')
-- AND TO_DATE('03-MAR-22 23:59:59', 'DD-MON-YY HH24:MI:SS'); --harcoded value works but I need to use input_date
AND 'TO_DATE' ||'(''' || input_date || ' 23:59:59''' ||',' || '''YYYY-MM-DD HH24:MI:SS''' ||')';
return data_out;
END getRecordsForDate;
My concatenation is not working in the last line. It gives me ORA-01858: a non-numeric character was found where a numeric was expected. Not sure what's wrong here. Would someone be able to help.
Do not use TO_DATE on a DATE.
The last line of the cursor will not work as it is a (concatenated) string literal that cannot be converted to a TIMESTAMP or a DATE.
Even if it did work (which it will not), your purchase_date is a TIMESTAMP(6) data type so you are going to exclude all value from the time 23:59:59.0000001 until 23:59:59.999999.
You want to use:
create or replace FUNCTION getRecordsForDate(
input_date DATE DEFAULT SYSDATE
) RETURN sys_refcursor
IS
data_out SYS_REFCURSOR;
BEGIN
OPEN data_out FOR
SELECT product_name,
product_type,
purchased_by
FROM product_details
WHERE purchase_date >= TRUNC(input_date)
AND purchase_date < TRUNC(input_date) + INTERVAL '1' DAY;
return data_out;
END getRecordsForDate;
/

Get resultset from a declare block

I've managed to incorporate variables into my pl/sql script and I get the correct result but I cannot figure out how to get it back in the same format as if I executed a plain select. I only see examples that use dbms_output.put_line which outputs text. How do I get an ordinary table out of this:
declare
monday date;
sunday date;
c sys_refcursor;
type t is table of MY_TABLE%rowtype;
r t;
begin
monday := (sysdate - 7 - to_char(sysdate, 'd') + 2);
sunday := (sysdate - 7 + to_char(sysdate, 'd'));
DBMS_OUTPUT.PUT_LINE(monday);
DBMS_OUTPUT.PUT_LINE(sunday);
select
*
bulk collect into
r
from
MY_TABLE
where
"Created On" >= monday and
"Created On" <= sunday
fetch next 10 rows only;
DBMS_OUTPUT.PUT_LINE(r.COUNT); -- <-- = 10
-- this might work but doesn't yet...
open c for select * from r;
DBMS_SQL.RETURN_RESULT(c);
close c;
end;
I found a way that it might be possible to use a cursor with DBMS_SQL.RETURN_RESULT but I still have issues with the r, it says ORA-00942 that the table name is invalid.

function/procedure to calculate total based on total for each month in plqsl

I need advice on how to write a stored procedure or function to calculate total based on total of each month. Lets say:
target income for Jan = 20K, then for a month: 20K * 31 (total days of January)
target income for Feb = 19K, then for a month 19K * 28 (total days of February)
I need to get total up to the given date. For instance:
date_param = 25 February 2018. Then grand total = (20K * 31) + (19K * 25)
How to write this in pl/sql?
Thank you.
Your question remains rather light on specifics, so here are my assumptions.
The daily targets are stored in a table with a structure of
(month_no number, daily_tgt number).
The targets are the same for each year.
The calculation starts from the first month of the current year.
There is no need to handle leap years.
The presented question rules out the need to handle non-working days.
This solution is a function to return the calculated total.
create or replace function get_target_sum
(p_cutoff in date)
return number
as
rv number;
begin
select sum(daily_tgt * no_of_days)
into rv
from (
select daily_tgt
, case when month_no < to_number(to_char(p_cutoff, 'MM'))
then to_number(to_char(last_day(to_date(month_no,'MM')), 'DD'))
else to_number(to_char(p_cutoff, 'DD'))
end as no_of_days
from targets
where month_no <= to_number(to_char(p_cutoff, 'MM'))
);
return rv;
end;
/
Notes
Storing the daily targets by numeric month make it easier to filter the months before the cut-off date in the WHERE clause.
Casting the month number to a date allows us to derive the last day of the month from which we get the number of days to multiply for whole months.
For the final month we just need the day from the cut-off date.
Your question is not very clear as in stating how to get the Monthly rates. I assumed few things and providing my solution as below:
1) Created a table mnthly_tgt which would store monthly rates.
2) The function will take an input date and then return the sum from past months of the year.
Table Definition:
Create table mnthly_tgt(mnth number, tgt_amt number);
insert into mnthly_tgt values(1 , 15);
insert into mnthly_tgt values(2, 20);
insert into mnthly_tgt values(3 , 12);
insert into mnthly_tgt values(4 , 10);
insert into mnthly_tgt values(5 , 11);
insert into mnthly_tgt values(6, 15);
insert into mnthly_tgt values(7, 20);
Function:
Create or replace function Ret_Tot(ipt_dt date)
return number
is
v_curr_mnth number;
v_curr_days number;
v_tot_amt number;
v_sql varchar2(400);
v_date date;
v_num_of_days number;
cntr number:=0;
begin
-- Calculating total for current month.
Select to_char(ipt_dt,'MM') col1 -- Current Month
,to_char(ipt_dt,'dd') col3 -- Days in Current Month
INTO
v_curr_mnth ,
v_curr_days
from DUAL;
-- Current Month Total
v_tot_amt: = v_curr_days * (Select tgt_amt from mnthly_tgt where mnth = v_curr_mnth);
--Calculation for previous months
For i in (Select to_char(ipt_dt,'MM') - LEVEL col1
from Dual
CONNECT BY LEVEL < to_char(col,'MM')
Loop
cntr := cntr + 1;
v_sql:='Select ipt_dt - INTERVAL '|| cntr ||' MONTH from DUAL' ;
Execute Immediate v_sql INTO V_DATE;
--calculating no. of days of previous months
v_sql:='SELECT EXTRACT(DAY FROM LAST_DAY('|| V_DATE ||')) FROM dual';
Execute Immediate v_sql INTO v_num_of_days ;
--Summing up total
v_tot_amt: = v_tot_amt + ( v_num_of_days * (Select tgt_amt from mnthly_tgt where mnth = i.col1));
END LOOP;
return v_tot_amt;
end;
PS: Nt tested.

how to check what the value of Parameter in Oracle PLSQL Procedure

I am in need of amending a procedure to include new data in which a parameter has been set. I need to check the value of the parameter so that I can test my code individually before it is implemented. below is portion of code which has parameter.
PROCEDURE Get_All_MT (i IN NUMBER)
AS
BEGIN
INSERT INTO mrr_reten_mt_obp_cli (
AMI_SCHEMA,
UAN,
PRODUCT_CLASS,
POL_NO
)
SELECT a.ami_schema,
a.uan,
a.product_class,
a.pol_no
FROM mrr_retention_c_cover_item a,
att_axa_uan agt,
amt_structure str
WHERE a.accident_date BETWEEN TRUNC (ADD_MONTHS (SYSDATE, i - 1), 'MONTH')
AND TRUNC (ADD_MONTHS (SYSDATE, i), 'MONTH')
- (1 / (60 * 60 * 24))
As you can see parameter "I" is been used in for accident_date range. I need to know what is the value of I so that it can be replaced while the code is been executed individually.
Log the value using DBMS_OUTPUT:
PROCEDURE Get_All_MT (i IN NUMBER)
AS
BEGIN
DBMS_OUTPUT.PUT_LINE( i );
INSERT INTO ...
I would create table log_params (param varchar2(30), value varchar2(200), log_time date); and procedure:
create or replace procedure log_param(param varchar2(30), value varchar2(200)) as
pragma autonomous transaction
begin
insert into log_params values (param, value, sysdate);
commit;
end;
/
And include in your code: log_param('i', i);. Then examinate results in table log_params

oracle function to return list of dates as object

To whom it may respond to ,
I am trying to return list of dates and weekdays to be used in other functions. Code below is compiled without error. But it should give output of 15 days (via V_MAX_DAYS variable) and number of the day in that week.
I have tried to implement like this, but cannot get output using DBMS_OUTPUT. I want to test it but got ORA-06532 error at when running .
My aim is to return values to asp.net application as we have done using SYS_REFCURSOR.
How can I achieve that?
Thank you for your concern,
The script is as below :
CREATE OR REPLACE TYPE DATE_ROW AS OBJECT
(
WEEKDAY_VALUE DATE,
DATE_IN_LIST VARCHAR2(5)
)
/
CREATE OR REPLACE TYPE DATE_TABLE as table of DATE_ROW
/
CREATE OR REPLACE FUNCTION FN_LISTDATES
RETURN DATE_TABLE
IS
V_DATE_TABLE DATE_TABLE := DATE_TABLE ();
V_MAX_DAYS NUMBER := 15;
V_CALCULATED_DATE DATE;
V_WEEKDAY VARCHAR2 (5);
BEGIN
FOR X IN -2 .. V_MAX_DAYS
LOOP
SELECT TO_DATE (TO_CHAR (SYSDATE + X, 'DD.MM.YYYY'))
INTO V_CALCULATED_DATE
FROM DUAL;
V_DATE_TABLE.EXTEND;
V_DATE_TABLE(X) := DATE_ROW(V_CALCULATED_DATE, 'Test');
END LOOP;
RETURN V_DATE_TABLE;
END;
/
A few points.
If you want a DATE (V_CALCULATED_DATE) that is X days from SYSDATE with the time component set to midnight, which appears to be your intent here, you would want something like v_calculated_date := TRUNC(sysdate) + x;. A TO_DATE without an explicit format mask is going to create issues if a future session's NLS_DATE_FORMAT happens not to be DD.MM.YYYY
If you really want to return a collection like this, your collection indexes would need to start with 1, not -2. You could accomplish that by doing v_date_table(x+3) := DATE_ROW(v_calculated_date, 'Test');.
However, I would tend to suspect that you would be better served here with a pipelined table function.
The pipelined table function would look something like
SQL> ed
Wrote file afiedt.buf
1 CREATE OR REPLACE FUNCTION FN_LISTDATES
2 RETURN DATE_TABLE
3 PIPELINED
4 IS
5 V_MAX_DAYS NUMBER := 15;
6 V_CALCULATED_DATE DATE;
7 V_WEEKDAY VARCHAR2 (5);
8 BEGIN
9 FOR X IN -2 .. V_MAX_DAYS
10 LOOP
11 v_calculated_date := trunc(sysdate) + x;
12 PIPE ROW( DATE_ROW(v_calculated_date,'Test') );
13 END LOOP;
14 RETURN;
15* END;
SQL> /
Function created.
SQL> select * from table( fn_listDates );
WEEKDAY_V DATE_
--------- -----
30-NOV-10 Test
01-DEC-10 Test
02-DEC-10 Test
03-DEC-10 Test
04-DEC-10 Test
05-DEC-10 Test
06-DEC-10 Test
07-DEC-10 Test
08-DEC-10 Test
09-DEC-10 Test
10-DEC-10 Test
WEEKDAY_V DATE_
--------- -----
11-DEC-10 Test
12-DEC-10 Test
13-DEC-10 Test
14-DEC-10 Test
15-DEC-10 Test
16-DEC-10 Test
17-DEC-10 Test
18 rows selected.

Resources