how to display number value in words - sql

Q. Display the number value in Words and output should look like this
SAL In_Words
--------- -----------------------------------------------------
800 eight hundred
1600 one thousand six hundred
1250 one thousand two hundred fifty
And, I'm still didn't figure out, how this query is the solution for the above output.
select sal, to_char(to_date(sal,'j'),'Jsp') in_words from emp
What to_date is doing here ? Anyone have any idea about this query ?

So how the query works? Well here’s why:
select to_char(to_date(:number,'j'),'jsp') from dual;
If you look into the inner most part of the query to_date(:number,'j') the ‘j’ or J is the Julian Date (January 1, 4713 BC), basically this date is been used for astronomical studies.
So to_date(:number,'j') it take the number represented by number and pretend it is a julian date, convert into a date.
If you pass 3 to number, so it will convert date to 3rd Jan 4713 BC, it means 3 is added to the Julian date.
select to_char(to_date(3,'j'),'jsp') from dual;
Now to_char(to_date(3,'j'),'jsp'), jsp = Now; take that date(to_date(3,'j')) and spell the julian number it represents, the output is:
TO_CH
-----
three
There is a limitation while using Julian dates ,It ranges from 1 to 5373484. That’s why if you put the values after 5373484, it will throw you an error as shown below:
ORA-01854: julian date must be between 1 and 5373484
Hi everyone, it is interesting this topic. I remember when I was learning Oracle in 2005 one of the instructor required me to write a PL/SQL code to convert numbers in words, it was a whole two pages code to reach this.
Here is some reference that could help us to understand the Julian day, that is why we use the letter 'j' or 'J' during this operation.
First there is a website that has the example and explanation about "How To Convert Number Into Words Using Oracle SQL Query":
http://viralpatel.net/blogs/convert-number-into-words-oracle-sql-query/
Second if you want to know more about "Julian day" go to:
http://en.wikipedia.org/wiki/Julian_day
Third if you want to know more about who proposed the Julian day number in 1583, it was by "Joseph Scaliger":
http://en.wikipedia.org/wiki/Joseph_Justus_Scaliger
It is not make sence for me continue repiting what another author in these websites have made, that is why I just posted the link you can access them and read what you need to understand how query like this works:
SELECT TO_CHAR (TO_DATE (2447834, 'j'), 'jsp') FROM DUAL;
//Output: two million four hundred forty-seven thousand eight hundred thirty-four

I've never heard of a DBMS with a built-in function to do as you ask. You'll need a table of number-names, to join to that once per digit using modulo arithmetic, and string concatenation to produce one In_Words column. Plus some logic to eliminate leading zeros. It will take time to write.

J stands for Julian day - the number of days since January 1, 4712 BC. The numbers in your table converted to Julian date. JSP spells out the date:
SELECT to_char(SYSDATE,'JSP') AS number_of_days_sinse_4712_BC
FROM dual
/

to convert decimal number into words, you can follow below code
SELECT TO_CHAR(to_date(TRUNC(num),'J'),'Jsp')
||' and '
|| TO_CHAR(to_date(to_number(SUBSTR(num-TRUNC(num),instr(num-TRUNC(num),'.')+1)),'J'),'Jsp') Indicator
FROM
(SELECT &enter_numbr num FROM dual
);
Hope this will help!!!

Related

Oracle SQL: Is There a Maximum Date Difference Oracle Can Interpret

I'm working on sql that looks for rows in a table where the rows 'last_run' date + 'frequency' (in minutes), is greater than the current date/time. I've noticed that there appears to be an upper bound for date comparisons Oracle can make sense of.
For example this query;
with tests as
(
select
'TEST 1' as code,
99999999 as frequency,
sysdate as last_run
from dual
union
select
'TEST 2' as code,
99999999999 as frequency,
sysdate as last_run
from dual
)
select
p.*,
(p.last_run + p.frequency / 24 / 60 ) as next_run
from tests p
where (p.last_run + p.frequency / 24 / 60 < sysdate or p.last_run is null)
I would expect this query to return null but instead it returns;
CODE
FREQUENCY
LAST_RUN
NEXT_RUN
TEST 2
99999999999
05-OCT-2021 10:15:46 AM
15-APR-4455 08:54:46 PM
I can solve the problem by setting frequency = null and my other code will recognize that the row need not be considered, but it seems strange to me that Oracle can't recognize that the year 4455 > 2021.
Is there some maximum conceivable date in Oracle that I'm unaware of?
I'm running this in Oracle SQL Developer Version 18.2.0.183 and Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production.
it seems strange to me that Oracle can't recognize that the year 4455 > 2021
It can. The problem is that your year isn't 4455; it's -4455. See this db<>fiddle, showing the result (in a different timezone) with default DD-MON-RR format, your output format, and ISO format with the year sign included (S format element).
CODE
FREQUENCY
LAST_RUN
NEXT_RUN
TEST 2
99999999999
2021-10-05 17:16:21
-4454-03-12 03:55:21
With your frequency of 99999999999 the value you are adding to the current date is 69444444 days, which is (very roughly) 190128 years - clearly that's going to put you well past the maximum date of 9999-12-31; and indeed with a different value like 9999999999 (one less digit), which is 6944444 days or roughly 19012 years, you get an error - also shown in that db<>fiddle.
The issue seems to be how Oracle manipulates its internal representation when it does the calculation; in adding that large value it appears that the year - which is stored in two bytes - is overflowing and wrapping.
Using the type-13 version, 190128+2021 = 192149, which is (256 * 750) + 149. 750 doesn't fit in one byte, so you get the modulus, which is 238. That would make the first two bytes of the calculated date come out as 149,238. That actually corresponds to year -4459:
select dump(date '-4459-01-01') from dual;
Typ=13 Len=8: 149,238,1,1,0,0,0,0
which is close enough to demonstrate that's what's happening - given that the calculation is outside the expected range and it's probably trying to do invalid leap day calculations in there somewhere. The point, though, is that the generated, wrapped, value represents a valid year in that internal notation.
With the lower value, 19012+2021 = 20133, which is (256 * 82) + 41. Now there is no wrapping, so the first two bytes of the calculated date come out as 41,82. That is now not a valid year, so Oracle knows to throw the ORA-01841 exception.
So, you need to limit the frequency value to a number that won't ever go past 9999-12-31, or test it at run time against 9999-12-31 minus the current date - and if it's too big, ignore it. That's if you want what appears to be a magic number at all.
There is a maximum date in Oracle, it is 9999-12-31 23:59:59 in YYYY-MM-DD HH24:MI:SS format. Here is a screenshot of the Oracle Documentation:
Here is the Oracle Documentation which talks about the valid date values (LINK)
The problem is that you are adding ~190,258 years with your second query. Likely overflowing the buffer many times over. It just so happened that you ended up back at the value you did.

Ingres multiplication gives wrong result

I have an Ingres table with following columns
from_date ingresdate
to_date ingresdate
model_amt money
The dates can reflect a period of any number of days, and the model_amt is always a weekly figure. I need to work out the the total model_amt for the period
To do this I need to know how many days are covered by the period, and then divide model_amt by 7, and multiply it by the number of days
however, I am getting incorrect results using the code below
select model_amt, date_part('day',b.to_date - b.from_date),
model_amt / 7 * int4( (date_part('day',b.to_date - b.from_date)) )
from table
For example, where model_amt = 88.82 and the period is for 2 weeks, I get the following output
+-------------------------------------------------------+
¦model_amt ¦col2 ¦col3 ¦
+--------------------+-------------+--------------------¦
¦ #88.82¦ 14¦ #177.66¦
+-------------------------------------------------------+
But 88.82 / 7 * 14 = 177.64, not 177.66?
Any ideas what is going on? The same issue happens regardless of whether I include the int4 function around the date_part.
* Update 15:28 *
The solution was to add a float8 function around the model_amt
float8(model_amt)/ 7 * interval('days', to_date - from_date)
Thanks for the responses.
In computers, floating point numbers are notoriously inaccurate. You can multiply do all kinds of basic mathematics calculations on floating point numbers and they'll be off by a few decimals.
Some information can be found here; but its very googleable :). http://effbot.org/pyfaq/why-are-floating-point-calculations-so-inaccurate.htm
Generally to avoid inaccuracies, you need to use a language specific feature (e.g. BigDecimal in Java) to "perfectly" store the decimals. Alternatively, you can represent decimals as separate integers (e.g. main number is one integer and the decimal is another integer) and combine them later.
So, I suspect this is just ingres showing the normal floating point inaccuracies and that there are known workarounds for it in that database.
Update
Here's a support article from Actian specifically about ingres floating point issues which seems useful: https://communities.actian.com/s/article/Floating-Point-Numbers-Causes-of-Imprecision.

Detecting Invalid Dates in Oracle 11g database (ORA-01847 )

I am querying an Oracle 11.2 instance to build a small data mart that includes extracting the date of birth and date of death of people.
Unfortunately the INSERT query (which takes its data from a SELECT) fails due to ORA-01847 (day of month must be between 1 and last day of month).
To find my bad dates I first did:
SELECT extract(day FROM SOME_DT_TM),
extract(month FROM SOME_DT_TM),
COUNT(*)
FROM PERSON
GROUP BY extract(day FROM SOME_DT_TM), extract(month FROM SOME_DT_TM)
ORDER BY COUNT(*) DESC;
It gave me 367 rows, one for each day of the year including NULL and February-29th (leap year). True for the other date column as well, so it looks like the data is fine from a SELECT perspective.
However if I set logging up on my insert
create table registry_new_dates
(some_dob date, some_death_date date);
exec dbms_errlog.create_error_log('SOME_NEW_DATES');
And then run my long insert query:
SELECT some_dob,some_death_date,ora_err_mesg$ FROM ERR$_SOME_NEW_DATES;
I get the following weird results (first 3 rows shown) which makes me think that zip codes have been somehow inserted instead of dates for the 2nd column.
31-DEC-25 35244 "ORA-01847: day of month must be between 1 and last day of month"
13-DEC-33 35244-3402 "ORA-01847: day of month must be between 1 and last day of month"
23-JUN-58 35235 "ORA-01847: day of month must be between 1 and last day of month"
My question is - how do I detect these bad rows (there are 11 apparentlyh) with an SQL statement so I can fix or remove them. Fixing them in the originating table is not an option (no write privileges). I tried using queries like this:
SELECT DECEASED_DT_TM
FROM WH_CLN_PERSON
WHERE DECEASED_DT_TM LIKE '35%'
AND rownum<3;
But it did not find the offending rows.
Not sure if you are still actively researching this (or if you got an answer already).
To find the rows with the bad data, can't you instead select the DOB and the date of death, and express the WHERE clause in terms of DOB - like so:
...WHERE some_dob = to_date('31-DEC-25')
? After you find those rows, you may want to do another query on just one or two of those rows, including a calculated column: dump(date of death). Then post that. We can learn a lot from the dump - the internal representation of the so-called "date" (which may very well be a ZIP code instead). With that in hand we may be able to figure out what's stored, and how to hunt for it.

SQLite Convert String to Date when date column has single digit months and days

I am trying to mimic the solution in this answer post: Sqlite convert string to date
The problem I am running into though is that my raw text date field contains dates in the following format:
1/5/2014 0:00:00
instead of:
01/05/2014 0:00:00
How can I account for this single digit month/day variability and adapt the code for my purpose? I cannot think of a decent way. I have thought of using excel to create a conversion table that I could join upon. Is there a more elegant approach?
Edit on 10/2/2014:
I would have thought there would be more like 81 possible combinations to identify. Or Maybe there is a simpler way I am not thinking of?
1/1/
1/2/
1/3/
1/4/
1/5/
1/6/
1/7/
1/8/
1/9/
2/1/
2/2/
2/3/
2/4/
2/5/
2/6/
2/7/
2/8/
2/9/
...
There are eight different combinations of one- or two-digit fields; you just have to check for all of them:
SELECT CASE
WHEN Trans_Date LIKE '_/_/____ _:__:__' THEN substr(Trans_Date, 10, 1)
WHEN Trans_Date LIKE '_/_/____ __:__:__' THEN substr(Trans_Date, 10, 2)
...
END AS Hour,
...
FROM LS2014

Getting the range in SQL when given between

I am wondering if it's possible (without actually parsing the given string) to get the actual range (in terms of days, minutes or seconds) that is specified when you have an SQL statement like
[select 'x'
from dual
where date between to_date('20111113152049')
and to_date('20120113152049')]
I am working on a query where I'm given a string in the form of
"between to_date(A) and to_date(B)"
and would like to get that value in days to compare to a policy we let the user set so they don't enter a date range longer than say a week.
Assuming you're looking for a theoretical answer (that is: don't take this into production) this could work:
Prerequistes:
have three tables: days_seq(day_seq), month_seq(mth_seq) and year_seq(yr_seq)
days has the numbers 1...31, month 1..12, years 2011....?
Use te following query (I used access because I don't have proper RDBMS available here, keep in mind that MS-ACCESS/JET is forgiving in the use of the Dateserial function, that is, it doesn't break when you ask the dateserial for february, 30th, 2012)
SELECT Max(DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
, [days_seq]![day_seq]))
-
Min(DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
,[days_seq]![day_seq])) AS days
FROM days_seq, month_seq, year_seq
WHERE DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
,[days_seq]![day_seq])
BETWEEN #2012-02-1# AND #2012-02-28#
The query basically produces a carthesian product of three tables which generates all possible days in months, months in a year for as many years as you have in the years table.
Bonus:
You could off-course generate a permanent Calendar table as X-Zero suggests.
table calendar([date])
INSERT INTO calendar
SELECT DISTINCT DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
, [days_seq]![day_seq]))
FROM days_seq, month_seq, year_seq
You still have to pick your start year and your end year wisely. According to the Maya's an enddate of december 21st, 2012 will do.