The width of a columns is known before execution.
Well, in most cases…
SELECT TO_CHAR(SYSDATE,'DAY','NLS_DATE_LANGUAGE=FRENCH')
FROM DUAL;
TO_CHAR(
--------
SAMEDI
The length is as most 8 characters (VENDREDI). Therefore the width of the column is 8.
SELECT TO_CHAR(SYSDATE,'YEAR') FROM DUAL;
TO_CHAR(SYSDATE,'YEAR')
------------------------------------------
TWO THOUSAND EIGHT
Oracle thinks the length is at most 42 characters. This is a bad guess, the year 7777 is the longest to spell and is only 27 characters. So the width is 42.
SELECT TO_CHAR(SYSDATE,'JSP') FROM DUAL;
TO_CHAR(SYSDATE,'JSP')
---------------------------------------------------------
---------------------
TWO MILLION FOUR HUNDRED FIFTY-FOUR THOUSAND SIX HUNDRED
EIGHTY-EIGHT
again, this is a bad guess, the maximum length of a spelled Julian day is 77 (May 9, 4388) not 78.
let’s try with spelling the nanoseconds :
select to_char(current_timestamp,'FF9SP') from dual;
TO_CHAR(CURRENT_TIMESTAMP,'FF9SP')
-------------------------------------------------------
-----------------------
SEVENTY-FOUR MILLION
here 78 is a really bad guess… the nanoseconds could be 100 character long !
What happened then :
select to_char(timestamp '0001-01-01 00:00:00.777777777',
'FFSP') from dual;
select to_char(timestamp '0001-01-01 00:00:00.777777777',
*
ERROR at line 1:
ORA-01877: string is too long for internal buffer
The query fails. Does it means the maximum length returned by TO_CHAR is 78? Not at all!
It simply means Oracle sets the width column to something too small to contain the result.
By setting the column to something longer, the query should work…
select cast(to_char(timestamp '0001-01-01 00:00:00.
777777777','FFSP') as varchar2(100)) from dual;
CAST(TO_CHAR(TIMESTAMP'0001-01-0100:00:00.777777777','FFSP')
------------------------------------------------------------
ASVARCHAR2(100))
----------------------------------------
SEVEN HUNDRED SEVENTY-SEVEN MILLION SEVEN HUNDRED SEVENTY-
SEVEN THOUSAND SEVEN HUNDRED SEVENTY-SEVEN
Ok, let’s do something perverse
Let set the CURSOR_SHARING to FORCE !
Have a look :
SQL> alter session set cursor_sharing='FORCE';
Session altered.
SQL> select to_char(to_date(1000000,'J'),'JSP') from dual;
TO_CHAR(TO_DATE(1000000,'J'),'JSP')
----------------------------------------------------------
-----------------
ONE MILLION
the width of the column is evaluated to 75. 75 however is not the maximum length!
SQL> select to_char(to_date(1777777,'J'),'JSP') from dual;
select to_char(to_date(1777777,'J'),'JSP') from dual
*
ERROR at line 1:
ORA-01801: date format is too long for internal buffer
Not only CURSOR_SHARING=FORCE influence the output of the query, but it also make the SQL failing.
Let’s revert to EXACT for confirmation.
SQL> alter session set cursor_sharing='EXACT';
Session altered.
SQL> select to_char(to_date(1000000,'J'),'JSP') from dual;
TO_CHAR(TO_
-----------
ONE MILLION
SQL> select to_char(to_date(1777777,'J'),'JSP') from dual;
TO_CHAR(TO_DATE(1777777,'J'),'JSP')
--------------------------------------------------------------
--------------
ONE MILLION SEVEN HUNDRED SEVENTY-SEVEN THOUSAND SEVEN HUNDRED
SEVENTY-SEVEN
“Oracle thinks the length is at most 42 characters. This is a bad guess”
It doesn’t make things any clearer but the answer really is 42.
SQL> select to_char(add_months(date ‘0001-01-01′,(-12*rownum)),’YEAR’),
2 length(to_char(add_months(date ‘0001-01-01′,(-12*rownum)),’YEAR’))
3 from dual;
TO_CHAR(ADD_MONTHS(DATE’0001-01-01′,(-12*R
——————————————
LENGTH(TO_CHAR(ADD_MONTHS(DATE’0001-01-01′,(-12*ROWNUM)),’YEAR’))
—————————————————————–
000000000000000000000000000000000000000000
42
Of course, it does leave open, what is the actual question….
Hi Laurent:
The ‘Oracle Certification Professionals’ blog is a forum for candidates to share their exam preparation approach/strategy and their test taking experiences.
I’m starting a weekly feature on the blog called “Meet the Experts”.
With your permission, I would like to publish a Q&A session with you.
Future candidates would greatly benefit from your advice and be encouraged to pursue a certification path.
Please reply with your approval so that I can send the list of questions for the Q&A to you.
Thanks in advance,
Mohan, a.k.a. OCP Advisor
OCP Blog – http://ebizocp.blogspot.com
Laurent, what version are you talking about :
SQL> alter session set cursor_sharing='FORCE';
Session altered.
SQL> select to_char(to_date(1777777,'J'),'JSP') from dual;
TO_CHAR(TO_DATE(1777777,'J'),'JSP')
----------------------------------------------------------------------------
ONE MILLION SEVEN HUNDRED SEVENTY-SEVEN THOUSAND SEVEN HUNDRED SEVENTY-SEVEN
SQL> select * from v$version where rownum=1;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
SQL>
nicolas, it is a bit tricky, your first query must return something smaller. Try to bounce the instance and start with 1000000 before 17777777