Quarterly Dates Calculation [XQuery] - xquery

I am trying to generate a report which fetches quarterly report i.e. based on startDate and endDate. How to calculate startDate and endDate of any quarter if I have quarter name as Q1 and year as parameters in XQuery or Marklogic.
Example: if I have Quarter=q1 and Year=2018 as parameters, then I need to get startDate as 01-01-2018 and endDate as 31-03-2018

You could use functx:last-day-of-month() and other standard date functions to construct the start and end date for the given year and quarter.
The example code below will return a sequence of xs:date objects with the first being the start date, and the second the end date.
xquery version "1.0-ml";
import module namespace functx = "http://www.functx.com"
at "/MarkLogic/functx/functx-1.0-doc-2007-01.xqy";
declare function local:quarter-range($year as xs:integer, $quarter as xs:integer) {
let $month := 3 * $quarter
let $end := xs:date($year || "-"|| substring(string(100 + $month), 2)||"-01")
let $start-date := $end - xs:yearMonthDuration("P2M")
let $end-date := functx:last-day-of-month($end)
return
($start-date, $end-date)
};
local:quarter-range(2018, 2)
You could enhance that to instead construct and return a cts:and-query() with cts:element-range-query:
xquery version "1.0-ml";
import module namespace functx = "http://www.functx.com"
at "/MarkLogic/functx/functx-1.0-doc-2007-01.xqy";
declare function local:quarter-range(
$element as xs:QName,
$year as xs:integer,
$quarter as xs:integer)
as cts:query
{
let $month := 3 * $quarter
let $end := xs:date($year || "-"|| substring(string(100 + $month), 2)||"-01")
let $start-date := $end - xs:yearMonthDuration("P2M")
let $end-date := functx:last-day-of-month($end)
return
cts:and-query((
cts:element-range-query($element, ">=", $start-date),
cts:element-range-query($element, "<=", $end-date)
))
};
local:quarter-range(xs:QName("myDateElement"), 2018, 2)

Related

getting wrong number or types of arguments in call to procedure

I am trying to call a procedure using below code and getting
wrong number or types of arguments in call to procedure
The issue could be with the record type being passed as parameter , but I couldn't see any issue with that .
DECLARE
p_status VARCHAR2 (4) := 'S';
p_id NUMBER := 123456;
p_py_id NUMBER := 513;
p_type NUMBER := 1;
p_date_time DATE := TO_DATE ('10/01/2018 23:50:42', 'DD/MM/YYYY HH24:MI:SS');
p_os_pay NUMBER := 0;
p_ind VARCHAR2 (2) := 'Y';
p_confirm VARCHAR2 (2) := 'Y';
p_year NUMBER := 2018;
p_reason VARCHAR2 (5) := NULL;
p_currrpay NUMBER := 1517;
p_details pkg.g_r_type;
BEGIN
p_details.pro_code := 'AB';
p_details.inst_type := '1';
p_details.pay_date := TO_DATE ('19/10/2016 00:00:00', 'DD/MM/YYYY HH24:MI:SS');
p_details.pay_amt := 5000;
p_details.h_code := 'ABCD';
p_details.pay_ind := 'N';
p_details.c_code := 123456;
p_details.c_year := 8;
pkg.procedure_info ( p_status,
p_id,
p_py_id,
p_type,
p_date_time,
p_os_pay,
p_ind,
p_confirm,
p_year,
p_reason,
p_details,
p_currrpay
);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM);
END;
/
Below is the package description :
CREATE OR REPLACE package pkg
as
type g_r_type is record (
pro_code varchar2 (2)
,inst_type varchar2 (1)
,pay_date date
,pay_amt number (13, 2)
,h_code varchar2 (4)
,pay_ind varchar2 (1)
,c_code number(6)
,c_year number(2)
);
procedure procedure_info (
p_status in varchar2
,p_id in number
,p_py_id in number
,p_type in number
,p_date_time in date
,p_os_pay in number
,p_ind in varchar2
,p_confirm in varchar2
,p_year in number
,p_failure_reason in varchar2
,p_details in g_r_type
,p_currrpay in number
);
end pkg;
/
I have cross checked the datatypes, length and number of arguments , but couldn't find the issue.
Make sure your package scripts end with a / at the very end of the text file, as the first char of the line (and last non blank).
If your package was created successfully, you should get a message:
package created successfully
Then if your package's Body is:
package body created successfully
To make sure your package is correctly created on the database:
This query should help:
Select * from all_source where name='PKG';
And for the body:
Select *
from all_source
where name='PKG'
and type='PACKAGE BODY';

Need to remove timezone from current-date() xquery

I am a newbie in xquery and one of the requirement is to generate daily reports by querying xDB.
If I hardcode the date I am able to generate the report from xDB but if I try to read the current Date the from the system I don't get any values in report.
Code Snippet:
let $day := fn:current-date()
let $hours := ( '00', '01', '02', '03', '04',
'05', '06', '07', '08', '09',
'10', '11', '12', '13', '14',
'15', '16', '17', '18', '19',
'20', '21', '22', '23' )
let $ddhh := for $i in $hours return concat($day,"T",$i)
let $title := concat("Average Time By Documents in Hour on ", $day)
In report:
("Average Time By Documents in Hour on 2015-06-08Z"..)
The difference between hardcoded value and current-date() function is the timezone"Z". How do I get rid of timezone "Z". I only want say "2015-06-08" in variable $day and not "2015-06-08Z"
Thanks in advance.
If you want to get rid of the timezone component of the date, you can use fn:adjust-date-to-timezone(), using an empty sequence as the second parameter:
fn:adjust-date-to-timezone($day, ())
When casting a dateTime object to a string, the default ISO date format is chosen, always including the timezone. Convert the date manually instead using fn:format-dateTime($dateTime, $picture) with a date picture string $picture.
format-date(current-date(), "[Y0001]-[M01]-[D01]")
You can also add the hours in the desired format:
format-dateTime(current-dateTime(), "[Y0001]-[M01]-[D01]-[H01]")
This even enable you to omit the hour-sequence you pregenerated (of course also works in a single line, split up so it can be explained more easily):
let $today := current-date() (: today :)
let $today := xs:dateTime($today) (: convert to dateTime :)
let $hour := $today + xs:dayTimeDuration("PT3H") (: add 3 hours :)
return format-dateTime($hour, "[Y0001]-[M01]-[D01]-[H01]")

ORA-21700 on SELECT FROM package-user-defined TABLE

I'm creating an Oracle package (MyPackage) where I have a public custom type table (ObjDataCollection) of custom type records (ObjData), which will be used as IN parameter for one of the Package functions (Calculate):
CREATE OR REPLACE PACKAGE MyPackage AS
TYPE ObjData IS RECORD (
t date NOT NULL := DATE '0001-01-01',
v number(9, 4)
);
TYPE ObjDataCollection IS TABLE
OF ObjData;
FUNCTION Calculate(
DataSource IN ObjDataCollection
) RETURN number;
END MyPackage;
CREATE OR REPLACE PACKAGE BODY MyPackage AS
FUNCTION Calculate(
DataSource IN ObjDataCollection
) RETURN number IS
res number(9, 4) := 0;
dateStart date;
dsv ObjData;
CURSOR q1 (dt date) IS
SELECT * FROM TABLE(DataSource) --Throws ORA-21700: Object does not exist or is marked for delete oracle.
WHERE t >= dt
ORDER BY t;
BEGIN
-- some irrelevant code
dateStart := DATE '2015-01-01';
OPEN q1(dateStart);
LOOP FETCH q1 INTO dsv;
EXIT WHEN q1%NOTFOUND;
res := res + dsv.v;
-- some irrelevant code
END LOOP;
CLOSE q1;
-- some irrelevant code
return res;
END Calculate;
END MyPackage;
I debbuged my code and I get the error on the second line of the cursor (marked in code):
ORA-21700: Object does not exist or is marked for delete oracle.
I'm using this data to execute my package:
CREATE TABLE TestTable (d date DEFAULT DATE '0001-01-01', v number(9, 4));
INSERT INTO TestTable VALUES (DATE '2015-01-01', 2.1);
INSERT INTO TestTable VALUES (DATE '2015-01-08', 3.1);
INSERT INTO TestTable VALUES (DATE '2015-01-15', 4.1);
INSERT INTO TestTable VALUES (DATE '2015-01-22', 5.1);
INSERT INTO TestTable VALUES (DATE '2015-01-29', 6.1);
INSERT INTO TestTable VALUES (DATE '2015-02-05', 7.1);
And this code to run a test:
CREATE OR REPLACE PROCEDURE TestMyPackage AS
res MyPackage.ObjDataCollection;
counter number(9, 4);
BEGIN
SELECT d, v
BULK COLLECT INTO res
FROM TestTable
ORDER BY v;
counter := MyPackage.Calculate(res);
END TestMyPackage;
Why I recieve this ORA-21700 exception?
PACKAGE BODY MyPackage AS
FUNCTION Calculate(
DataSource IN ObjDataCollection
) RETURN number IS
res BINARY_FLoAT:= 0;
dateStart date;
dsv ObjData;
copy_of_DataSource ObjDataCollection;
procedure sortCollection(toSort in out ObjDataCollection)
is
type idx_coll is table of ObjData;
type sort_help is table of idx_coll index by varchar2(16 char);
v_sort sort_help;
v_temp varchar2(16);
v_result ObjDataCollection := new ObjDataCollection();
v_cnt PLS_INTEGER := 0;
begin
for i in nvl(toSort.first,1) .. nvl(toSort.last,-1) loop
v_temp := to_char(toSort(i).t,'yyyymmddhh24miss');
if v_sort.exists(v_temp) then
v_sort(v_temp).extend(1);
v_sort(v_temp)(v_sort(v_temp).count) := toSort(i);
else
v_sort(v_temp) := idx_coll(toSort(i));
end if;
end loop;
v_result.extend(toSort.count);
v_temp := v_sort.first;
while v_temp is not null loop
for i in nvl(v_sort(v_temp).first,1) .. nvl(v_sort(v_temp).last,-1) loop
v_cnt := v_cnt +1;
v_result(v_cnt) := v_sort(v_temp)(i);
end loop;
v_temp := v_sort.next(v_temp);
end loop;
toSort := v_result;
end;
BEGIN
-- some irrelevant code
copy_of_DataSource := DataSource;
dateStart := DATE '2015-01-01';
sortCollection(copy_of_DataSource);
for i in nvl(copy_of_DataSource.first,1) .. nvl(copy_of_DataSource.last,-1) loop
if copy_of_DataSource(i).t > dateStart then
res := res + copy_of_DataSource(i).v;
dbms_output.put_line(copy_of_DataSource(i).t);
end if;
end loop;
-- some irrelevant code
return res;
END Calculate;
END MyPackage;
As it was a task due to a date, I ended up fixing it by creating user-defined types and tables at schema level as suggested Arkadiusz Ɓukasiewicz in one of his comments. Thank you for your effort.
As is not what I wanted, I won't mark any answer as Correct.
Got the same problem and solved it by doing the following steps:
Drop package where type is defined
Drop package using that type
Compile package with type
Compile target package
I got this ORA-21700 after adding new constants in a package with types/constants. I guess there's some internal issue with dependencies but I haven't dug a lot.

Get result set in plsql

am wondering if there already some rewriting suggestions to get functions such generating recurrence dates between two dates - generate_recurrences() from this link for recurrency recurrency events
in plsql? it returns a setof date, but in plsql i can't figure out how to get a resultset for dates and looping return next next_date, where next also returns a next date on a list.
I tried it to rewrite it in plsql but with only return of one date, because i can't find out how to return a resultset in plsql, that what i've tried:
CREATE OR REPLACE FUNCTION GENERATE_RECURRENCE( rec in VARCHAR2,
start_date in TIMESTAMP,
end_date in TIMESTAMP )
RETURN TIMESTAMP
IS
next_date TIMESTAMP := start_date;
duration INTERVAL DAY TO SECOND;
day INTERVAL DAY TO SECOND;
BEGIN
IF recurs = 'none' THEN
return next_date;
elsif recurs = 'daily' then
duration := INTERVAL '1' DAY ;
while next_date <= end_date loop
return next_date + duration;
END IF;
END;
I wrote the following pipelined function a while ago. It's not exactly what you're asking for, but it gives you a resultset that's a range of dates, so you should be able to match it to your needs.
It requires you to create a type object to hold the return value and I used an existing object instead of creating a custom one. So you should modify this to use an object just big enough (and use date type instead of string). But the functionality does what you're asking for.
Enjoy!
CREATE OR REPLACE FUNCTION date_range_stream(start_date_in IN DATE,
end_date_in IN DATE) RETURN rpt_results_10_obj_type_type
DETERMINISTIC
PIPELINED IS
/*
Parameters: start_date_in - First date to return (truncated)
end_date_in - Last date to return, inclusive
Results: date string formatted as MM/DD/YYYY
Author: Stew Stryker
Usage: SELECT to_date(text01, 'MM/DD/YYYY') AS a_date
FROM TABLE(aeo.aeo_misc_tools.date_range_stream('01-MAR-2009', SYSDATE))
Returns a rows from starting date to current
Requires the definition of the following object:
CREATE OR REPLACE TYPE rpt_results_10col_obj AS OBJECT
( seq_num NUMBER,
place VARCHAR2(20),
rep_info VARCHAR2(20),
text01 VARCHAR2(512),
text02 VARCHAR2(512),
text03 VARCHAR2(512),
text04 VARCHAR2(512),
text05 VARCHAR2(512),
text06 VARCHAR2(512),
text07 VARCHAR2(512),
text08 VARCHAR2(512),
text09 VARCHAR2(512),
text10 VARCHAR2(512));
*/
cur_date DATE := trunc(start_date_in);
date_row rpt_results_10col_obj := aeo.rpt_results_10col_obj(NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
BEGIN
WHILE cur_date <= trunc(end_date_in)
LOOP
date_row.text01 := TO_CHAR(cur_date, 'MM/DD/YYYY');
PIPE ROW(date_row);
cur_date := cur_date + 1;
END LOOP;
RETURN;
EXCEPTION
WHEN no_data_found THEN
RETURN;
WHEN OTHERS THEN
dbms_output.put_line('EXCEPTION IN aeo.aeo_misc_tools.date_range_stream - ' || SQLCODE || ': ' ||
SQLERRM);
RAISE;
RETURN;
END date_range_stream;

How to get starting and ending date from last year in plsql

I have a plsql function count_order_cust with three parameters. But p_start and p_end are optional. If I call function with three parameters, then function is executed well, but if I call function with one parameter p_id, then it has to count orders for last year (i.e. 01/Jan/2013 - 31/Dec/2013) and this is my problem. How can I do this?
Here is function count_order_cust:
CREATE OR REPLACE FUNCTION count_order_cust(p_id f_customers.id%TYPE, p_sd f_orders.order_date%TYPE DEFAULT NULL, p_ed f_orders.order_date%TYPE DEFAULT NULL)
RETURN NUMBER IS v_count_orders NUMBER(3) := 0;
BEGIN
SELECT COUNT(cust_id) INTO v_count_orders
FROM f_orders
WHERE cust_id = p_id AND f_orders.order_date BETWEEN p_sd AND p_ed;
RETURN v_count_orders;
EXCEPTION WHEN NO_DATA_FOUND THEN RETURN NULL;
END count_order_cust;
With this select I get date in last year, but I need have in p_sd = '01/Jan/2013' and in p_ed = '31/Dec/2013'.
select add_months(sysdate,-12) from dual;
The below code shows you how to derive the required dates, then bundle the code into functions which can be used as the default parameters of your procedure:
declare
function getFirstDayOfLastYear return date is
begin
return trunc(add_months(sysdate,-12),'YEAR');
end;
function getLastDayOfLastYear return date is
begin
return trunc(sysdate,'YEAR') - 1;
end;
procedure myProc(
p_start date default getFirstDayOfLastYear,
p_end date default getLastDayOfLastYear
) is
begin
dbms_output.put_line(p_start);
dbms_output.put_line(p_end);
end;
begin
myProc;
end;

Resources