Oracle random date and time - oracle

I am using the code below to generate random dates, which works fine.
Can this be modified to add a random time to the date between from 00:00:00 - 23:59:59
My attempt below failed and I'm unsure why. Any help would be greatly appreciated.
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
SELECT TO_DATE(
TRUNC(
DBMS_RANDOM.VALUE(TO_CHAR(DATE '2021-01-01','J')
,TO_CHAR(DATE '2022-12-31','J')
)
),'J' +
NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(0,86399)), 'SECOND')
) FROM DUAL;

You have brackets in the wrong place:
SELECT TO_DATE(
TRUNC(
DBMS_RANDOM.VALUE(
TO_CHAR(DATE '2021-01-01','J'),
TO_CHAR(DATE '2022-12-31','J')
)
),
'J'
)
+ NUMTODSINTERVAL(
FLOOR(DBMS_RANDOM.VALUE(0,86399)),
'SECOND'
)
FROM DUAL;
Note: it helps if you format your code so that indentation matches the brackets and then you can more easily spot errors like this.
You can simplify the code to:
SELECT DATE '2021-01-01'
+ NUMTODSINTERVAL(
DBMS_RANDOM.VALUE(0, DATE '2022-12-31' - DATE '2021-01-01' + 1),
'DAY'
)
FROM DUAL;
Or, even simpler:
SELECT DATE '2021-01-01'
+ DBMS_RANDOM.VALUE(0, DATE '2022-12-31' - DATE '2021-01-01' + 1)
FROM DUAL;
db<>fiddle here

Related

Oracle adding randim amount if seconds to a date

I have a date that is always set to midnight i.e. '07312021 00:00:00' how can I use dbms_random.value to add (1 second, 23:59:59) to that date.
SELECT DATE '2021-07-31' + INTERVAL '1' SECOND * FLOOR(DBMS_RANDOM.VALUE(0, 86400))
FROM DUAL;
Or
SELECT DATE '2021-07-31' + NUMTODSINTERVAL(
FLOOR(DBMS_RANDOM.VALUE(0, 86400)),
'SECOND'
)
FROM DUAL;
Or
SELECT DATE '2021-07-31' + DBMS_RANDOM.VALUE
FROM DUAL;
sqlfiddle here

Date of release from 1-jan-xx year until now

I create query which display all item which is cancel in period
start.date - end.date
select substr(tarifa,1,2) as tarifa, count(*) as komada
from pol p, uvod u, doppov d
WHERE (datum_dop >='1-jan-07') AND (datum_dop<='1-jul-13')
and izdavanje>='01-jul-10'
and p.orgjed = u.sorgz (+)
and p.polica=d.polica and d.pov_dopl='P'
--and DATUM_PREKIDA is not null
and d.status='F'
and cisti_ao(p.polica)!=0
group by substr(tarifa,1,2)
Now I want to edit this query column izdavanje. If user enter '27-sep-xx year' it need to display item in period start-date '01-jan-xx' until '27-sep-xx year'
So start date need to be always '1-jan-xx year' and end date need to be entered date like '19-aug-xx'.
Any idea how to fix this problem ?
This:
and izdavanje>='01-jul-10'
will become
and izdavanje between to_date('01.01.' || substr(:BLOK.IZDAVANJE, -2), 'dd.mm.rr')
and to_date(:BLOK.IZDAVANJE, 'dd-mon-rr')
substr will return xx year
to_date will convert the whole value into a valid date
Now, as it is Forms, you might need to adjust it a little bit (depending on column datatype as well as form item's datatype), but - that's the general idea.
You want to use TRUNC( date_value, 'YY' ) to truncate it to the start of the year:
AND izdavanje BETWEEN TRUNC( '01-jul-10', 'YY' ) AND '01-jul-10'
However, you should also note that '01-jul-10' is a text literal so, when a date is required, Oracle has to perform an implicit conversion from the text literal to a date. You would be better performing an explicit conversion (as Oracle's default format is the NLS_DATE_FORMAT session parameter and ANY user can change this value in their own session and changing that will break your query without any modification of your code).
For example, to perform an explicit cast to a date:
AND izdavanje BETWEEN TRUNC(
TO_DATE( '01-jul-10', 'DD-MON-RR', 'NLS_DATE_LANGUAGE = American' ),
'YY'
)
AND TO_DATE( '01-jul-10', 'DD-MON-RR', 'NLS_DATE_LANGUAGE = American' )
Also, if your izdavanje date values have time components then '01-jul-10' will be converted to a date at midnight (00:00:00) so you will not get any values returned for that day that have time components between 2010-07-01 00:00:01 and 2010-07-01 23:59:59. If this is relevant and you want those values returned then you should use:
AND izdavanje >= TRUNC(
TO_DATE( '01-jul-10', 'DD-MON-RR', 'NLS_DATE_LANGUAGE = American' ),
'YY'
)
AND izdavanje < TO_DATE( '01-jul-10', 'DD-MON-RR', 'NLS_DATE_LANGUAGE = American' )
+ INTERVAL '1' DAY
You can modify a date inside a query using TO_CHAR() function:
Instead of:
and izdavanje>='01-jul-10'
use this:
and izdavanje between TO_CHAR( :BLOK.IZDAVANJE, 'YYYY-01-01' )
and TO_CHAR( :BLOK.IZDAVANJE, 'YYYY-MM-DD 23:59:59' )
TO_CHAR( :BLOK.IZDAVANJE, 'YYYY-01-01' ) takes only the year from the date and adds '-01-01' (January 1st) to it.
TO_CHAR( :BLOK.IZDAVANJE, 'YYYY-MM-DD 23:59:59' ) adds the max time of the day to the date because 'between xxx and yyy' means equal or less than 00:00:00 of day yyy and all timestamps with a timestamp greater than 00:00:00 but the same day won't be covered when using time values in :BLOK.IZDAVANJE.

TO_DATE ISSUE IN CONVERSION

I tried to execute the below query but it's throwing me error :
SELECT TO_DATE(
TIMESTAMP '1970-01-01 00:00:00' + numtodsinterval(1511421211, 'second')
,'DD-MM-YYYY HH24:MI:SS')
FROM dual
Error : ORA-01830: date format picture ends before converting entire input string
The TO_DATE( datestring, format_model ) function takes strings as arguments.
Your query:
SELECT TO_DATE(
TIMESTAMP '1970-01-01 00:00:00' + numtodsinterval(1511421211, 'second')
,'DD-MM-YYYY HH24:MI:SS'
)
FROM dual
Is passing a TIMESTAMP and a string so Oracle has to perform an implicit conversion from TIMESTAMP to a string so your function is effectively:
SELECT TO_DATE(
TO_CHAR(
TIMESTAMP '1970-01-01 00:00:00' + numtodsinterval(1511421211, 'second'),
(
SELECT value
FROM NLS_SESSION_PARAMETERS
WHERE parameter = 'NLS_TIMESTAMP_FORMAT'
)
),
'DD-MM-YYYY HH24:MI:SS'
)
FROM dual
If the NLS_TIMESTAMP_FORMAT session paramter does not match your format model 'DD-MM-YYYY HH24:MI:SS' then an exception will be raised.
You could change the NLS_TIMESTAMP_FORMAT parameter - but this is a session parameter that is set per user and each user can change it at any time during their session so this should NOT be the solution.
Instead, you can just use a DATE literal instead of a TIMESTAMP literal:
SELECT DATE '1970-01-01' + NUMTODSINTERVAL (1511421211, 'second')
FROM DUAL
Or, if you want to use a timestamp then you can use the CAST function:
SELECT CAST(
TIMESTAMP '1970-01-01 00:00:00' + NUMTODSINTERVAL (1511421211, 'second')
AS DATE
)
FROM DUAL
Is this what you are expecting?
select to_char(DATE '1970-01-01' + NUMTODSINTERVAL (1511421211, 'second'), 'yyyy/mm/dd hh24:mi:ss') from dual;
The syntax appear somewhat incorrect to me. Try this:
SELECT TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
+ NUMTODSINTERVAL (1511421211, 'second')
FROM DUAL;
Edit:
As #a_horse.. said "Oracle DATE always contains a time",so if timestamp is not visible then you just need to see your NLS_DATE_FORMAT in table V$NLS_PARAMETERS. In your case its simply set to
NLS_DATE_FORMAT = 'DD-MM-YYYY';
So you need to alter the session first to get the timestamp in SQLPLUS. See below:
SQL> alter session set NLS_DATE_FORMAT = 'mm-dd-yyyy HH24:mi:ss';
Session altered.
SQL> SELECT TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + NUMTODSINTERVAL (15114212
11, 'second') FROM DUAL;
TO_DATE('1970-01-01
-------------------
11-23-2017 07:13:31

how to truncate yyyy/mm/dd hh:mm:ss.SSS to mm/dd/yyyy in oracle

When I ran a query to get date it is retrieved in this format 'yyyy/mm/dd hh:mm:ss.SSS' but I need to convert it to mm/dd/yyyy.
I'm using this query for conversion
select
to_char(
add_months (
to_date(
to_char(
trunc(
TO_DATE('2016/01/01 00:00:00.0', 'YYYY/MM/DD HH24:MI:SS.SSS')
), 'MM/DD/YYYY' -- to char
),'MM/DD/YYYY' -- to date
), -2*1 -- add months
), 'MM/DD/YYYY' -- to char
) START_DATE,
to_char(
add_months (
to_date(
to_char(
trunc(
TO_DATE('2017/01/01 00:00:00.0', 'YYYY/MM/DD HH24:MI:SS.SSS')
), 'MM/DD/YYYY' -- to char
), 'MM/DD/YYYY' -- to date
), 3 -- add months
), 'MM/DD/YYYY' -- to char
) END_DATE
from dual;
Output is
ORA-01810: format code appears twice
01810. 00000 - "format code appears twice"
The problem is in the conversion of to_date itself. The below conversion itself is throwing the error you mentioned
select
TO_DATE('2017/01/01 00:00:00.0', 'YYYY/MM/DD HH24:MI:SS.SSS') END_DATE
from dual;
You need to use it like below if you want to convert the string with timestamp to timestamp
select TO_TIMESTAMP('2017/01/01 00:00:00.0', 'YYYY/MM/DD HH24:MI:SS.FF') from dual
This will simply satisfy your need rather than making so many conversions.
select to_char(
add_months(
TO_TIMESTAMP('2017/01/01 00:00:00.0', 'YYYY/MM/DDHH24:MI:SS.FF'),
-2),
'mm/dd/yyyy') from dual
ORA-01810: format code appears twice
That's because of SS.SSS. SSS is not a valid date format. You are trying to handle fractional seconds but:
the correct format mask for that is FF
DATE doesn't support fractional seconds, only TIMESTAMP
Really date format is a display issue and should be handled by the client's NLS settings. But if you really must do it in SQL this is all you need:
select
to_char(DATE '2015-11-01', 'MM/DD/YYYY') START_DATE
, to_char(DATE '2017-04-01', 'MM/DD/YYYY') END_DATE
from dual;
You don't need trunc() because the date literals are already set to midnight. You don't need add_months() because you can just change the value of the date literal. You don't need to cast the date to a string back to a date because you just don't.

Coalesce statement to handle multiple values and NULLS?

I am trying to figure out how to create an SQL query that will check for (:FROM_DATE) and (:TO_DATE) parameters and if NULL to put the past month dates in for the two values, and if not NULL to accept whatever values are entered in the parameters.
For example:
if the user enters (01-JAN-17) as FROM_DATE, and (31-JAN-17) as TO_DATE, I want the query to not automatically pass any values for the TO_DATE and FROM_DATE.
if the user does not enter any values for TO_DATE and FROM_DATE or there are NULL values passed in, I want the query to automatically enter the the past months values (i.e., if query is run July 1st 2017, the FROM_DATE would be 01-JUN-17 and the TO_DATE would be 30-JUN-17).
I was hinted to use a coalesce statement to handle multiple values and NULLS (i.e., AND ( (coalesce(null, :P_ORG) is null) or (ORG.ORGANIZATION_ID in :P_ORG)))???
Any help would be greatly appreciated.
Something like:
SELECT *
FROM your_table
WHERE your_date_column BETWEEN TO_DATE( :from_date, 'DD-MON-YYYY' )
AND TO_DATE( :to_date, 'DD-MON-YYYY' )
OR ( ( :from_date IS NULL OR :to_date IS NULL )
AND your_date_column BETWEEN ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), -1 )
AND TRUNC( SYSDATE, 'MM' ) - 1
);
If either (or both) :from_date or :to_date is NULL then the dates will be compared to the previous month.
If your table has dates where the time component is not always set to midnight then you will need to use:
SELECT *
FROM your_table
WHERE your_date_column BETWEEN TO_DATE( :from_date, 'DD-MON-YYYY' )
AND TO_DATE( :to_date, 'DD-MON-YYYY' )
OR ( ( :from_date IS NULL OR :to_date IS NULL )
AND your_date_column >= ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), -1 )
AND your_date_column < TRUNC( SYSDATE, 'MM' )
);
Proof of concept: consider the following query, where we have dates and values, and we want to sum the values for the dates that fall between :from_date and :to_date. If either of them is null, the query will use the first day of the prior month for from_date and the last day of the prior month for to_date. Note that this will cause problems if one date is given an actual value and the other is left null - you didn't explain how you would want that handled. But that's a different issue.
I use SQL developer, and in it I don't know how to pass in dates; I show passing in strings, and converting them to dates.
with
test_data ( dt, val ) as (
select date '2017-05-29', 200 from dual union all
select date '2017-06-13', 150 from dual union all
select date '2017-06-18', 500 from dual
)
select sum(val) as sum_val
from test_data
where dt between coalesce(to_date(:from_date, 'yyyy-mm-dd'),
add_months(trunc(sysdate, 'mm'), -1))
and coalesce(to_date(:to_date , 'yyyy-mm-dd'), trunc(sysdate, 'mm') - 1)
;
Yes, you can use COALESCE (or Oracle's NVL). When a parameter is null, replace it with the default date.
select *
from mytable
where mydate >= coalesce(:from_date, trunc(sysdate - interval '1' month), 'month')
and mydate <= coalesce(:to_date, last_day(sysdate - interval '1' month));

Resources