How do declare date variables in PL/SQL? - sql

I am new to PL/SQL and don't understand how to declare date variables. How would I write this T-SQL script in PL/SQL?
declare #date1 as date
declare #date2 as date
set #date1 = '2022-06-01'
set #date2 = '2022-06-30'
select *
from example_table
where example_date between #date1 and #date2

Declaring variables is easy.
Problem comes when you want to do something with the select statement as PL/SQL requires you to select INTO something (a local variable, set of local variables, ref cursor, collection, ...). You didn't say what you'd want to do afterwards, so the following example
selects number of rows that satisfy condition
loops through the table and does nothing (null;) for each loop iteration.
You'd do something else, I presume.
declare
date1 date := date '2022-06-01';
date2 date := date '2022-06-30';
l_cnt number;
begin
select count(*)
into l_cnt
from example_table
where example_date between date1 and date2;
for cur_r in (select *
from example_table
where example_date between date1 and date2
)
loop
null;
end loop;
end;
/

Related

Create a function that accepts two dates, and returns the number of adverts that were posted between these two dates

I am having trouble with a work sheet how do I do this
create or alter function prac1.advert
(#date1 date, #date2 date)
returns date
begin
return()
end;
go
all i need is the format so that i can just implement the values i need myself
number of adverts in integer
Try like this (T-SQL):
create function prac1.fn_numberOfAdvertsBetweenDates(
#date1 date
, #date2 date
)
returns int
as
begin
declare #numberOfAdverts int;
set #numberOfAdverts = (
select
isnull(count(*), cast(0 as int))
from TableOfAdverts
where DateColumn >= #date1
and DateColumn < #date2
);
return(numberOfAdverts);
end;

Get first and last day of month into variables - Oracle

I would like to declare some variables that contain the first and last date of the current month in Oracle. I know how to get these values, but evidently not store or use them; I am more of a T-SQL guy.
In T-SQL, I could write:
DECLARE #startDate DATE = GETDATE();
DECLARE #endDate DATE = EOMONTH(GETDATE());
SELECT *
FROM SomeTable
WHERE SomeDate BETWEEN #startDate AND #endDate;
I cannot, for the life of me, work out how to do this in Oracle. I have tried several variations, like:
DECLARE END_DT DATE := TRUNC(LAST_DAY(SYSDATE))
END_DT DATE := TRUNC(LAST_DAY(SYSDATE))
DECLARE END_DT DATE;
SELECT TRUNC(LAST_DAY(SYSDATE)) INTO END_DT FROM DUAL;
I am mostly using 11g, but I would like to be able to use the same script on a 9i/10g server also.
You can use such a query to detect first and last days of the current month :
SELECT TRUNC(LAST_DAY(ADD_MONTHS(SYSDATE,-1)))+1,
TRUNC(LAST_DAY(SYSDATE))
INTO :startDate,:endDate
FROM DUAL;
with the contribution of ADD_MONTHS() function
Update : Alternatively use this PL/SQL code block :
DECLARE
startDate date;
endDate date;
BEGIN
startDate := TRUNC(LAST_DAY(ADD_MONTHS(SYSDATE,-1)))+1;
endDate := TRUNC(LAST_DAY(SYSDATE));
DBMS_OUTPUT.PUT_LINE ('startDate : '||startDate);
DBMS_OUTPUT.PUT_LINE ('endDate : '||endDate);
END;
/
Demo
You can use the LAST_DAY and TRUNC combination as following:
DECLARE
START_DT DATE := TRUNC(SYSDATE, 'MM');
END_DT DATE := TRUNC(LAST_DAY(SYSDATE));
BEGIN
--DBMS_OUTPUT.PUT_LINE(START_DT || ' ' || END_DT);
SELECT
*
INTO <...>
FROM
SOMETABLE
WHERE
SOMEDATE BETWEEN START_DT AND END_DT;
END;
/
Cheers!!

Oracle select with variables

Declare startdate date;
enddate date;
lastname nvarchar2(30);
Begin
Lastname := 'ZZZ';
startdate := '04-JAN-18';
enddate := '02-JUN-18';
insert into temp_feed
select empname, startdate, enddate , activityid, source, actname from emp_activity
where startdate >= startdate and enddate <= enddate and lower(LASTNM) like lower(lastname||'%')
End;
when I hardcode date values its working fine, but when I use variables the result is null.
am I missing something?
its recommended to use V_ before the name of variables and also P_ before the name of parameters, the problem in your code is you are comparing a value in table with itself at:
startdate >= startdate and enddate <= enddate
I do format your code and use the standard naming format here:
DECLARE
V_STARTDATE DATE;
V_ENDDATE DATE;
V_LASTNAME NVARCHAR2 (30);
BEGIN
V_LASTNAME := 'ZZZ';
V_STARTDATE := TO_DATE('04-JAN-18', 'DD-MON-YY');
V_ENDDATE := TO_DATE('02-JUN-18', 'DD-MON-YY');
INSERT INTO TEMP_FEED
SELECT EMPNAME, STARTDATE, ENDDATE, ACTIVITYID, SOURCE, ACTNAME
FROM EMP_ACTIVITY
WHERE STARTDATE >= V_STARTDATE
AND ENDDATE <= V_ENDDATE
AND LOWER (LASTNM) LIKE LOWER (V_LASTNAME || '%');
END;
I would recommend you to convert your variable to Date format first.
if you use function and it gets an parameter from outside, we can p_start_date for a date. Then you can try to convert out parameter to date format for sure.
v_start_date := to_date(p_start_date,'dd-MON-yyyy') ;
also in where clause
to_date(startdate,'dd-MON-yyyy') >= to_date(p_start_date,'dd-MON-yyyy')

creating max date function using sql in databricks

I am writing queries in databricks using sql on views and would like to calculate max of dates of update timestamp column across multiple views. for instance i am joining table a with table b and would like to know max(a.updt_ts,b.updt_ts). since max function can not have more than one columns mentioned, i want to create a function. Any help is greatly appreciated.
below is what i have:
CREATE temporary FUNCTION ufnGetMaxDt (#Date1 DATETIME2,#Date2 DATETIME2)
BEGIN
DECLARE #ret DATETIME2
, #MinDt datetime2;
SET #MinDt = cast('1900-01-01' as datetime2);
IF (#Date1) is null SET #Date1 = #MinDt;
IF (#Date2) is null SET #Date2 = #MinDt;
SET #ret = CASE When #Date1 >= #Date2
Then #Date1
else #Date2
END;
IF (#ret IS NULL)
SET #ret = #MinDt; -- Dummy date
RETURN #ret;
END
GO
You could just use greatest? eg
SELECT *, GREATEST( date1, date2 ) xmax
FROM tmp
Or put them in an array, explode it and then max that? eg something like this:
%sql
WITH cte AS
(
SELECT *, EXPLODE( ARRAY( date1, date2 ) ) xmax
FROM tmp
)
SELECT MAX( xmax )
FROM cte
Seems a bit excessive when you can just use greatest though? It's also worth having a read through the list of Spark SQL built-in functions. You don't have to remember them all but at least if you know something is possible it's useful:
https://spark.apache.org/docs/2.3.0/api/sql/index.html

PostgreSQL date difference

I have a PostgreSQL function which calculates date difference:
CREATE OR REPLACE FUNCTION testDateDiff () RETURNS int AS $BODY$
DECLARE startDate TIMESTAMP;
DECLARE endDate TIMESTAMP;
DECLARE diffDatePart int ;
BEGIN
Select evt_start_date From events Where evt_id = 5 INTO startDate ;
Select evt_start_date From events Where evt_id = 6 INTO endDate ;
SELECT EXTRACT(day FROM TIMESTAMP startDate - endDate) INTO diffDatePart;
RETURN diffDatePart;
END;
$BODY$
LANGUAGE plpgsql
COST 100
If dates are subtracted directly then difference is calculated. But in my case dates are present in variables as startDate and endDate, which causes the problem.
How can I subtract dates contained in variables?
Debug
What your function is doing could be done much simpler. The actual cause for the syntax error is here:
SELECT EXTRACT(day FROM TIMESTAMP startDate - endDate) INTO diffDatePart;
It looks like you are trying to cast startDate to timestamp, which is nonsense to begin with, because your parameter startDate is declared as timestamp already.
It also does not work. I quote the manual here:
To avoid syntactic ambiguity, the type 'string' syntax can only be
used to specify the type of a simple literal constant.
It would work like this:
SELECT EXTRACT(day FROM startDate - endDate)::int INTO diffDatePart;
But that still wouldn't make a lot of sense. You are talking about "dates", but still define your parameters as timestamp. You could sanitize what you have like this:
CREATE OR REPLACE FUNCTION f_date_diff()
RETURNS int AS
$BODY$
DECLARE
start_date date;
end_date date;
date_diff int;
BEGIN
SELECT evt_start_date FROM events WHERE evt_id = 5 INTO start_date;
SELECT evt_start_date FROM events WHERE evt_id = 6 INTO end_date;
date_diff := (endDate - startDate);
RETURN date_diff;
END
$BODY$ LANGUAGE plpgsql;
DECLARE only needed once.
date columns declared as proper type date.
Don't use mixed case identifiers, unless you know exactly what you are doing.
Subtract the start from the end to get a positive number or apply the absolute value operator #.
Since subtracting dates (as opposed to subtracting timestamps, which yields an interval) already yields integer, simplify to:
SELECT (startDate - endDate) INTO diffDatePart;
Or even simpler as plpgsql assignment:
diffDatePart := (startDate - endDate);
Simple query
You can solve the simple task with a simple query - using a subquery:
SELECT (SELECT evt_start_date
FROM events
WHERE evt_id = 6)
- evt_start_date AS date_diff
FROM events
WHERE evt_id = 5;
Or you could CROSS JOIN the base table to itself (1 row from each instance, so that's ok):
SELECT e.evt_start_date - s.evt_start_date AS date_diff
FROM events e
,events s
WHERE e.evt_id = 6
AND s.evt_id = 5;
SQL function
If you insist on a function for the purpose, use a simple sql function:
CREATE OR REPLACE FUNCTION f_date_diff(_start_id int, _end_id int)
RETURNS int LANGUAGE sql AS
$func$
SELECT e.evt_start_date - s.evt_start_date
FROM events s, events e
WHERE s.evt_id = $1
AND e.evt_id = $2
$func$;
Call:
SELECT f_date_diff(5, 6);
PL/pgSQL function
If you insist on plpgsql ...
CREATE OR REPLACE FUNCTION f_date_diff(_start_id int, _end_id int)
RETURNS int LANGUAGE plpgsql AS
$func$
BEGIN
RETURN (SELECT evt_start_date
- (SELECT evt_start_date FROM events WHERE evt_id = _start_id)
FROM events WHERE evt_id = _end_id);
END
$func$;
Same call.
I would write the query like this:
create function testDateDiff()
returns integer as $$
declare
startDate timestamp;
endDate timestamp;
begin
startDate := (select evt_start_date From events Where evt_id = 5);
endDate := (select evt_start_date From events Where evt_id = 6);
return (select extract(day from startDate - endDate));
end;
$$ language 'plpgsql';
The difference between using := and into in the context above is that using := your query must return a single value. If you use into your query can return a single row (i.e. more than one column).
For a full explanation of using select with into and plpgsql you should read http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html. Specifically, section 39.5.3 of the PostgreSQL documentation.
Do you really need a function for this?
This query would work as well:
SELECT (SELECT evt_start_date::date FROM events WHERE evt_id = 5)
- evt_start_date::date
FROM events WHERE evt_id = 6;