I am new to oracle and as part of a project I was trying add or concatenate date value to serial id
generator in my sql insert column .
The query generating serial numbers is
select nvl(max(RII_INDENT_ID_SL),0 +1 ID from T_RAKE_INDENT_IBMD)
This query gives output in the form of integers like 23,24 etc as serial numbers taking the maximum value and adding 1 thus creating new serial no.
In order to make it a unique ID I want to add sysdate value particularly the year and month to the result output.
so the result will be something like this:
1-23/09/2022
Can it be done by concatenating || the sysdate value?
Absolutely it could be done using || operator -
select nvl(max(RII_INDENT_ID_SL),0 +1 || TO_CHAR(SYSDATE, 'DD/MM/YYYY') ID
from T_RAKE_INDENT_IBMD)
Related
I want to create a large amount of mock data in a table (in Postgresql). The schema of the table looks like this
price float,
id id,
period timestamptz
For price, this will be a random float number between 1-5
For id, this will be a value from another table that contain all value in id column (which may have a lot of id)
For period, this will generate a random datetime value in a specific range of time.
Here, I want to create a single query that can generate all these rows equal to amount of id I have to a specific range of time that I select.
E.g.
Let say I have 3 ids (a,b,c) in another table and I want to generate time series between 2019-08-01 00:00:00+00 and 2019-08-05 00:00:00+00
The result from this query will generate value like this:
price id period
3.4 b 2019-08-03 10:01:22+00
2.5 a 2019-08-04 05:44:31+00
4.8 c 2019-08-04 14:51:10+00
The price and id are random. Also period, but with specific range. Key thing is that, all ids need to be generated.
Generating random number and datetime is not hard but how can I create a query that can generate rows based on all id gathered from another table.
Ps. I have edited the example which might mislead my question
This answers a reasonable interpretation of the original question.
Getting a random value from a second table can be a little tricky. If the second table is not too big, then this works:
select distinct on (gs.ts) gs.ts, ids.id, cast(random() * 4.1 + 1 as numeric(2, 1))
from generate_series('2019-08-01 00:00:00+00'::timestamp, '2019-08-05 00:00:00+00'::timestamp, interval '30 minute') gs(ts) cross join
ids
order by gs.ts, random()
Use the function make_timestamptz generating a random integer for each part, except year and month. This will create random timestamps. As for getting the id from another table just select from that table.
/*
function to generate random integers. (Lots of then needed.)
*/
create or replace function utl_gen_random_integer(
int1_in integer,
int2_in integer)
returns integer
language sql volatile strict
as
$$
/* return a random integer between, inclusively, two integers, relative values of the integers does not matter. */
with ord as ( select greatest(int1_in, int2_in) as hi
, least(int1_in, int2_in) as low
)
select floor(random()*(hi-low+1)+l)::integer from ord;
$$;
-- create the id source table and populate
create table id_source( id text) ;
insert into id_source( id)
with id_range as ( select 'abcdefgh'::text idl)
select substring(idl,utl_gen_random_integer(1,length(idl)), 1)
from id_range, generate_series(1,20) ;
And the generation query:
select trunc((utl_gen_random_integer(1,4) + (utl_gen_random_integer(0,100))/100.0),2) Price
, id
, make_timestamptz ( 2019 -- year
, 08 -- month
, utl_gen_random_integer(1,5) -- day
, utl_gen_random_integer(1,24)-1 -- hours
, utl_gen_random_integer(1,60)-1 -- min
, (utl_gen_random_integer(1,60)-1)::float -- sec
, '+00'
)
from id_source;
The result generates the time at UTC (+00). However any subsequent Postgres will display the result converted to local time with offset. To view in UCT append "at time zone 'UCT'" to the query.
I have a table as admin_emp_leave_header which contains a column as START_DATE.
Suppose I use the following query to get those dates as:
select START_DATE sd
from admin_emp_leave_header;
I get following result
SD
--------
01-01-2017
02-01-2017
03-01-2017
04-01-2017
But I want the output as
SD
----------------------------------------------------
'01-01-2017','02-01-2017','03-01-2017','04-01-2017'
How do I get this using oracle?
You can convert a DATE to text using the TO_CHAR function and then concatenate these strings using the LISTAGG function:
SELECT LISTAGG(TO_CHAR(start_date,'''MM-DD-YYYY'''),',') WITHIN GROUP (ORDER BY start_date)
FROM admin_emp_leave_header
If you also needed to get the current date with the same format in case the previous query didn't return any records, you just need to use NVL:
SELECT NVL(LISTAGG(TO_CHAR(start_date,'''MM-DD-YYYY'''),',') WITHIN GROUP (ORDER BY start_date),TO_CHAR(SYSDATE,'''MM-DD-YYYY'''))
FROM admin_emp_leave_header
I have the following table:
ID DATE_START DATE_END
------- ---------- --------
11944 10.01.15 20.01.15
I would like to select rows based an a date range, e.g
01.01.15 - 25.01.15
15.01.15 - 25.01.15
In both cases I would like to select the column mentioned above. Is this possible with SQL? I tried a few things but i don't get the second query working. I use Oracle DB:
Example usage:
I want to query ma datatable like this: Show me all Entries between 15.01.15 and 25.01.15. This should yield to row with ID 11944
You want to return a row if two periods overlap, assuming both columns are defined as DATE.
select *
from tab
where DATE_START <= DATE '2015-01-25' -- end of searched period
and DATE_END >= DATE '2015-01-15' -- begin of searched period
In Standard SQL there's an OVERLAPS predicate which is not (officially) supported by Oracle:
where (DATE_START, DATE_END) OVERLAPS (DATE '2015-01-15', DATE '2015-01-25')
This is my Oracle query which gets records on the basis of date where differences of dates should be one month:
select *
from pbxhbl.HBL_TRANSACTIONS
where dat_creation between '10-apr-2013' and '10-jun-2013'
and MONTHS_BETWEEN('10-jun-2013','10-apr-2013') = 1
My question is, when difference is more than one I want to show a message:
'date duration should be one month'
MONTHS_BETWEEN('10-jun-2013','10-apr-2013')
Firstly, '10-jun-2013' is not a DATE, it is a STRING. Oracle will do an implicit data type conversion. Please avoid this, and always use TO_DATE to explicitly convert a string into date.
Secondly, months between the two dates that you have posted will never be 1, it will always be 2.
SQL> SELECT MONTHS_BETWEEN(to_date('10-jun-2013','dd-mon-yyyy'),to_date('10-apr-2013','dd-mon-yyyy')) dt
2 FROM dual;
DT
----------
2
SQL>
So, ideally your query will always return no rows.
SQL> SELECT *
2 FROM dual
3 WHERE MONTHS_BETWEEN(to_date('10-jun-2013','dd-mon-yyyy'),to_date('10-apr-2013','dd-mon-yyyy')) =1;
no rows selected
SQL>
Coming back to your question,
You could use a CASE expression.
However, if you are filtering out rows, then you would not have anything to display. So, remove the filter, such that whenever the value of MONTHS_BETWEEN is more than 1, you could return the message.
For example,
SQL> WITH DATA AS(
2 SELECT to_date('01-03-2015','DD-MM-YYYY') dt1, to_date('01-04-2015','DD-MM-YYYY') dt2 FROM dual UNION ALL
3 SELECT to_date('01-03-2015','DD-MM-YYYY') dt1, to_date('10-04-2015','DD-MM-YYYY') dt2 FROM dual UNION ALL
4 SELECT to_date('01-03-2015','DD-MM-YYYY') dt1, to_date('01-05-2015','DD-MM-YYYY') dt2 FROM dual
5 )
6 SELECT DT1,
7 DT2,
8 CASE
9 WHEN months_between(dt2, dt1) >1
10 THEN 'date duration should be one month'
11 ELSE 'OK'
12 END MESSAGE
13 FROM DATA;
DT1 DT2 MESSAGE
--------- --------- ---------------------------------
01-MAR-15 01-APR-15 OK
01-MAR-15 10-APR-15 date duration should be one month
01-MAR-15 01-MAY-15 date duration should be one month
SQL>
What you need should be done inside a function.
Create a function that takes two parameters as input (date, date) and as an output it returns a record of table type.
Inside a function, before passing your query to output insert a conditional control structure like CASE or IF to check whether or not given dates match your criteria. If yes, simply pass the query to the result, and if no (assuming you would like someone to see it in application) return a query that is built just as the record you would normally return and include your message in one of columns while the rest should remain NULL.
For the above I assumed that raising an error is not what you actually need.
Pseudocode:
CREATE FUNCTION check_dates_for_hbl_transactions(date, date)
RETURNS record
AS $function$
BEGIN
IF ( MONTHS_BETWEEN( $1 - $2 ) > 1 )
THEN RETURN QUERY SELECT 'Date duration should be one month at max'::text, NULL::bigint, ...
ELSE
RETURN QUERY SELECT * FROM HBL_TRANSACTIONS WHERE dat_creation BETWEEN $1 AND $2
END IF;
END
$function$
Important note: The reason I wrote 'message'::text, NULL::bigint, ... was to show that your select statement must match the returning set (in this case all the columns and their types from table HBL_TRANSACTIONS).
Also consider adding an additional check for date $2 to be larger than date $1 argument.
Side note: Consider returning rowtype to make it easier. I do not prefer that method as it is error prone in case of row type being changed. I'd rather have the function to fail and check manually for the cause than have it pass normally as usual with wrong value.
I would like to ask how do i check if the difference between two dates.
BillingDate which is a date type with an entry 'DD-MON-YYYY'
and the other date is the current date.
sys_date - BillingDate = daysFromBilled
alot of the examples i find they actually stated the second date to calculate the difference but what i am looking for is the difference between the current date so i can add it into a schedule or job.
i am using oracle btw.
Another point to add, i will continue to search, but if your could also recommend, how should i implement such a function:
Calculate date difference from all BillingDate entries
To trigger an alter table if the difference is more than 30 days to put Status as Late.
If Status is more than 60 days the Service attribute will be altered and changed to Cut
here is my rough table layout
Cust Billing
-------- ----------
CustID(PK) BillingID(PK)
LateStatus LateStatus
Service BillingDate
CustID
Thanks alot.
Update
REPLACE view DateDifference as
select trunc(sysdate)- trunc(BillingDate)
from Billing;
seems legit.
Simply subtract one date from the other:
BillingDate - sysdate
To do that in a select statement, just use it like this:
select billingdate - sysdate as daysFromBilled
from ...
Inside a trigger you use a regular assignment operator:
declare
daysFromBilled integer;
begin
daysFromBilled := :new.billingdate - sysdate;
...
that will return the number of days, including fractional values if the time is different (a DATE column in Oracle also contains a time!).
If you only want to get full days, use this:
trunc(BillingDate) - trunc(sysdate)
This statement of yours:
date type with an entry 'DD-MON-YYYY'
Indicates a misunderstanding on how DATE values work.
A DATE (or TIMESTAMP) does not have any format.
They are stored in binary form in your column. The format is only applied when you display the value and thus convert it to a character literal. That is the work of the client application you use to display the values. SQL*Plus uses the NLS settings, other SQL tools might use a different configuration.
All customers:
SELECT CUSTID
FROM BILLING
WHERE (SYSDATE - Billing_Date) >= 60
;
The following statement should update all the customer records where the difference is 60 days and over. Also, have added a clause to check if the service is already not set to CUT previously, so you don't end up updating the same records everytime.
UPDATE CUST_TABLE
SET SERVICE = 'CUT'
WHERE CustID in ( SELECT CustID
FROM BILLING_TABLE
WHERE (Sysdate - Billing_Date) >= 60
)
AND NVL(SERVICE, 'X') != 'CUT'
;