I working for a client who uses PROGRESS database SQL (i didn't knew this kind of database, so it's my first time that i work on it).
My problem it's all the dates are in Julian-date, and i want to convert them into datetime. But i haven't found any document or help online that deals with this.
The only document i found it's:
https://knowledgebase.progress.com/articles/Article/How-to-Obtain-a-Julian-Date-in-Progress
But i want to do exactly the opposite.
For example in postgresql:
select to_timestamp(column1::text,'J')
from table1
But on PROGRESS it's harder and there is less information and examples than the others databases on the web
Thank you in advance for your help
Character
In case your Julian date is stored in a field with the character data type, you can use instr to pull it apart and then reassemble it into a timestamp:
select
-- my character field containing 92182.3966
descr,
-- get the year
floor( cast( left( descr, instr( descr, '.' ) - 1 ) as integer ) / 1000 ) as 'year',
-- get the day
mod( cast( left( descr, instr( descr, '.' ) - 1 ) as integer ), 1000 ) as 'day',
-- get the time
cast(
'0' + right( descr, length( descr ) - instr( descr, '.' ) + 1 )
as float
) as 'time',
-- combine all to timestamp
cast(
-- get first day of year
cast(
to_char(
floor( cast( left( descr, instr( descr, '.' ) - 1 ) as integer ) / 1000 )
+ 1900 -- !!! beware
)
+ '-01-01'
as date
)
-- add days
+ mod( cast( left( descr, instr( descr, '.' ) - 1 ) as integer ), 1000 )
as timestamp
)
-- add milliseconds
+ cast(
cast(
'0' + right( descr, length( descr ) - instr( descr, '.' ) + 1 )
as float
) * 86400 * 1000
as integer
) as 'timestamp'
from pub.ddcapp
where application = 'JULIAN'
This reports that the time is 1992-07-01 09:31:06.24 which is 1 second later than what your link states it was translated from.
Decimal
If on the other hand your field is a decimal, it is a lot simpler:
select
-- my decimal field containing 92182.3966
open_bal,
-- get the year
floor( open_bal / 1000 ) as 'year',
-- get the day
mod( open_bal, 1000 ) as 'day',
-- get the time
open_bal - floor( open_bal ) as 'time',
-- combine all to timestamp
cast(
cast(
to_char(
floor( open_bal / 1000 )
+ 1900 -- !!!
)
+ '-01-01'
as date
)
+ mod( open_bal, 1000 )
as timestamp
)
+ ( open_bal - floor( open_bal ) ) * 86400 * 1000
as 'timestamp'
from pub.ledbal
where adm_nr = 0
Related
There is a requirement where I need to validate the identity card number with the first 6 digits as DOB. I need to find out the users not maintaining correct format.
If the dob is 02/10/1983 - 83021023456 && if its 02/10/2083 ->83221023456 (DOB is in MM/DD/YYYY and if year of birth >2000 then the +20 is done to the dob month). The query I tried with is given below:-
SELECT f_account_name,F_SSN ,F_DOB from table where
CASE WHEN SUBSTR(to_char(F_DOB, 'YYYY-MM-DD'),0,4)>2000
THEN
SUBSTR(f_ssn,0,6) <>
SUBSTR(to_char(F_DOB, 'YY-MM-DD'),0,2)
||SUBSTR(to_char(F_DOB, 'YY-MM-DD'),4,2)
||SUBSTR(to_char(F_DOB, 'YY-MM-DD'),7,2)
ELSE
SUBSTR(f_ssn,0,6) <>
SUBSTR(to_char(F_DOB, 'YY-MM-DD'),0,2)
||(SUBSTR(to_char(F_DOB, 'YY-MM-DD'),4,2)+20)
||SUBSTR(to_char(F_DOB, 'YY-MM-DD'),7,2)
END;
Its not working .
You cannot have the comparison inside the CASE expression; since the left-hand side of the expression is identical then it is simple to move it out and then you can simplify the rest:
SELECT f_account_name,
F_SSN,
F_DOB
FROM table_name
WHERE SUBSTR(f_ssn,0,6) !=
CASE
WHEN EXTRACT( YEAR FROM F_DOB ) > 2000
THEN TO_CHAR( F_DOB, 'YYMMDD')
ELSE TO_CHAR( F_DOB, 'YY' )
|| TO_CHAR( EXTRACT( MONTH FROM F_DOB )+20, 'FM00' )
|| TO_CHAR( F_DOB, 'DD')
END;
or, if the rule is to add 20 to the month for each century past 1900 (i.e. 20XX add 20 and 21XX add 40, etc.) then:
SELECT f_account_name,
F_SSN,
F_DOB
FROM table_name
WHERE SUBSTR(f_ssn,0,6) !=
TO_CHAR( F_DOB, 'YY' )
|| TO_CHAR(
EXTRACT( MONTH FROM F_DOB )
+ 20 * GREATEST( TRUNC( EXTRACT( YEAR FROM F_DOB ) / 100 ) - 19, 0 ),
'FM00'
)
|| TO_CHAR( F_DOB, 'DD');
I tried some date arithmetics and worked with numbers rather than strings ...
WITH
-- your input
indata(f_account_name,f_ssn,f_dob) AS (
--string -- number -- string
SELECT 'Arthur',83021023456,'02/10/1983' FROM dual
UNION ALL SELECT 'Tricia',83221023456,'02/10/2083' FROM dual
)
SELECT
f_account_name
, f_ssn
, f_dob
FROM indata
WHERE CAST(TRUNC(f_ssn/100000) AS NUMBER(6))
-- ^ integer division by 100000 to get the first 6 digits ...
= MOD(EXTRACT(YEAR FROM TO_DATE(f_dob,'MM/DD/YYYY')),100) * 10000
-- ^ modulo year of date of 100 gives 3rd and 4th digit of year
+ (
EXTRACT(MONTH FROM TO_DATE(f_dob,'MM/DD/YYYY'))
+CASE
WHEN EXTRACT(YEAR FROM TO_DATE(f_dob,'MM/DD/YYYY')) >= 2000 THEN 20
ELSE 0
END
) * 100
+ EXTRACT(DAY FROM TO_DATE(f_dob,'MM/DD/YYYY'))
;
I have a column called duration_d which is varchar2 and the data in that table looks like below
duration_d
-----------
12:25
01:35
12:10
04:21
12:18
12:24
I tried below query
SELECT SUM( to_date( duration_d, 'mi:ss' ))
FROM table
GROUP BY calling_number;
When I execute it following error is coming
ORA-00933: SQL command not properly ended
00933. 00000 - "SQL command not properly ended"
can any one tell me how to make sum it?
To get the total as fractions of a day you can use:
SELECT SUM( TO_DATE( duration_d, 'MI:SS' ) - TO_DATE( '00:00', 'MI:SS' ) ) AS total
FROM your_table
Which gives the result:
TOTAL
------------------------------------------
0.0383449074074074074074074074074074074074
To convert this to an interval data type you can use NUMTODSINTERVAL:
SELECT NUMTODSINTERVAL(
SUM( TO_DATE( duration_d, 'MI:SS' ) - TO_DATE( '00:00', 'MI:SS' ) ),
'DAY'
) AS total
FROM your_table
Which gives the result:
TOTAL
-------------------
+00 00:55:13.000000
Please try below:
with x as
(select sum((regexp_substr(YOUR_COLUMN, '[0-9]+', 1, 1)*60) +
regexp_substr(id, '[0-9]+', 1, 2)) seconds
from YOUR_TABLE)
SELECT
TO_CHAR(TRUNC(seconds/3600),'FM9900') || ':' ||
TO_CHAR(TRUNC(MOD(seconds,3600)/60),'FM00') || ':' ||
TO_CHAR(MOD(seconds,60),'FM00')
FROM x
Will work only if the duration is always [MI:SS].
Also you can add the group by as per your requirement.
Converting Seconds to the required duration format Reference.
Group By
with x as
(select calling_number,sum((regexp_substr(YOUR_COLUMN, '[0-9]+', 1, 1)*60) +
regexp_substr(id, '[0-9]+', 1, 2)) seconds
from YOUR_TABLE
group by calling_number)
SELECT calling_number,
TO_CHAR(TRUNC(seconds/3600),'FM9900') || ':' ||
TO_CHAR(TRUNC(MOD(seconds,3600)/60),'FM00') || ':' ||
TO_CHAR(MOD(seconds,60),'FM00')
FROM x
Use a combination of SUBSTR, to_char, to_date, NVL, INSTR, reverse and SUM.
SELECT "calling_number",
to_char(to_date(SUM(NVL(SUBSTR("duration_d", 0, INSTR("duration_d", ':')-1), "duration_d"))*60 +
SUM(substr("duration_d", - instr(reverse("duration_d"), ':') + 1)),'sssss'),'hh24:mi:ss') AS SUM_DURATION_D
FROM yourtable
GROUP BY "calling_number"
Output
calling_number SUM_DURATION_D
1 00:26:10
2 00:29:03
SQL Fiddle: http://sqlfiddle.com/#!4/9b0a81/33/0
Correct spelling as below
SELECT SUM( TO_DATE( duration_d, 'mi:ss' ) )
FROM YOURTABLE Group By calling_number
I am stucking by calculating the timestamp,how can i calculate/sum on different timestamp, example as below
Time (Timestamp in one column)
***********************
0:00:01
0:00:08
0:00:12
0:00:38
0:01:04
2:04:49
15:48:38
23:30:59
7:05:52
8:17:29
I want to show the sum(timestamp) in hh:mi.Any help?
i can tel you in postgresql you can do like
postgres=# select time '05:00' - time '03:00';
?column?
----------
02:00:00
(1 row)
dont know how much this can help you
This example works on DB2 when the values being added are TIME columns (as shown in original question). The trick is to convert the times to elapsed seconds, which are much easier to add up.
WITH origTbl (origTime) AS (VALUES
( TIME( '0:00:01' ) ),
( TIME( '0:00:08' ) ),
( TIME( '0:00:12' ) ),
( TIME( '0:00:38' ) ),
( TIME( '0:01:04' ) ),
( TIME( '2:04:49' ) ),
( TIME( '15:48:38' ) ),
( TIME( '23:30:59' ) ),
( TIME( '7:05:52' ) ),
( TIME( '8:17:29' ) )
)
,
totSeconds( secs ) AS (
SELECT SUM( MIDNIGHT_SECONDS( origTime ) )
FROM origTbl
)
SELECT RTRIM( CHAR( secs/3600 ) ) || ':' ||
LPAD( RTRIM( CHAR( MOD(secs, 3600)/60 ) ), 2, '0' ) || ':' ||
LPAD( RTRIM( CHAR( MOD(secs, 60) ) ), 2, '0' ) AS totHMMSS FROM totSeconds
;
TOTHMMSS
-----------------
56:49:50
1 record(s) selected.
I have looked into Cast and Convert, but I cannot find a way to do this. I need to convert four digits into an hour format. For instance, 0800 would become 8:00 or 1530 would become 15:30. I cannot use functions, I'm using a InterSystem's CacheSQL. Any suggestions? Thanks in advance!
EDIT:
If it is any more convenient, I can just divide the four digits by one hundred to get values like 15 from original 1500, or 8.30 from 0830. Does this make converting to hour:minute format easier?
For CacheSQL, you can do this:
SELECT {fn TRIM(LEADING '0' FROM LEFT(col_name, 2) || ':' || RIGHT(col_name, 2)) }
FROM table_name
In SQL Server 2008, given data that looks like
create table #data
(
HHMM int not null ,
)
insert #data values ( 0800 )
insert #data values ( 0815 )
insert #data values ( 1037 )
insert #data values ( 2359 )
You can say:
select * ,
strTime = right( '0' + convert(varchar, HHMM / 100 ) , 2 )
+ ':'
+ right( '0' + convert(varchar, HHMM % 100 ) , 2 ) ,
myTime = convert(time ,
right( '0' + convert(varchar, HHMM / 100 ) , 2 )
+ ':'
+ right( '0' + convert(varchar, HHMM % 100 ) , 2 ) ,
120
)
from #data
Other SQL implementations likely have similar functionality.
In earlier versions of SQL Server that lack the time datatype, just use datetime, thus:
select * ,
strTime = right( '0' + convert(varchar, HHMM / 100 ) , 2 )
+ ':'
+ right( '0' + convert(varchar, HHMM % 100 ) , 2 ) ,
myTime = convert(datetime,
right( '0' + convert(varchar, HHMM / 100 ) , 2 )
+ ':'
+ right( '0' + convert(varchar, HHMM % 100 ) , 2 ) ,
120
)
from #data
You'll get a datetime value that is 1 Jan 1900 with the desired time-of-day.
Well, if it is something like Oracle you might have a try with the to_date() function.
Read more here.
Example:
SELECT to_date(yourColumn, 'HH24MI') FROM ...
EDIT (why? see comments): If necessary (I'm actually not familiar with Oracle) you can wrap another function like TIME() around it.
SELECT TIME(to_date(yourColumn, 'HH24MI')) FROM ...
Read more about TIME() here.
</EDIT>
In MySQL the equivalent would be the STR_TO_DATE() function:
SELECT STR_TO_DATE(yourColumn, '%H%i') FROM ...
Read about STR_TO_DATE() and its parameters under the DATE_FORMAT() function.
left( case when (EndTime / 100) < 10 then ('0'+ convert(varchar, EndTime / 100 )) else convert(varchar, EndTime / 100 ) end, 2 )
+ ':'
+ right( '0' + convert(varchar, EndTime % 100 ) , 2 )
I need to convert Decimal to date. I have a decimal date field that contains data like this :
1,132,009.00 --1/13/2009
7,152,004.00 --7/15/2004
11,012,005.00 --11/01/2005
etc
I would like it to read as xx/xx/xxxx.
Is there anyway to do this with SQL commands or DB2 logic in a select statement?
SELECT column1 from table1 ;
WITH x(decvalue) AS ( VALUES (DECIMAL(1132009.00)),(DECIMAL(7152004.00)),(DECIMAL(11012005.00)) )
SELECT CAST(
LPAD( RTRIM( CHAR( INTEGER( decvalue/1000000 ))), 2, '0' ) || '/' ||
LPAD( RTRIM( CHAR( MOD( decvalue/10000, 100 ))), 2, '0' ) || '/' ||
MOD( decvalue, 10000 )
AS CHAR(10))
AS chardateresult
FROM x
;
Using the same WITH values as #Fred, I came up with:
WITH x(decvalue) AS ( VALUES (DECIMAL(1132009.00)),(DECIMAL(7152004.00)),(DECIMAL(11012005.00)) )
SELECT TO_DATE(CHAR(CAST(decvalue AS DECIMAL(8,0))), 'MMDDYYYY')
FROM x
This assumes that your input values aren't going to be longer than 8 digits (2 for month, 2 for day, 4 for year), otherwise you'll get an overflow error on the cast. It will also fail if there's not at least some value for each of month, day, and year (00002011 would not work, for example, but 01012011 would).