If you take a look at view user_tab_columns (or equivalent) you will find that its definition includes columns low_value and high_value, which give the currently known low and high value for the data. For example:
select column_name, low_value, high_value from user_tab_columns where table_name = 'T1' and column_name = 'SKEW' ; COLUMN_NAME LOW_VALUE HIGH_VALUE -------------------- --------------- --------------- SKEW C102 C151
This is fine, of course, if you are good at translating internal forms of data into human-readable forms.
For those of us less gifted, the dbms_stats package gives us some help with a set of procedures with names like convert_raw_value(). There are three overloaded functions to handle varchar2, date, and number types (with binary_float and binary_double appearing as new options in 10g), and two special cases: convert_raw_value_nvarchar() and convert_raw_value_rowid(). The procedures all take two parameters – the first in an input which is the raw value to be converted, the second is an output which has to be a variable of the correct type, so, for example:
SQL> declare 2 m_n number; 3 begin 4 dbms_stats.convert_raw_value('C102',m_n); 5 dbms_output.put_line('Result: ' || m_n); 6 end; 7 . SQL> / Result: 1
For convenience, you can wrap calls to the procedures inside functions, which then makes them available for use in SQL.
The following example is just to get you started (the column called skew is one I know to be a number type) – you would probably want to create a package to hold several different functions, and declare the functions as deterministic.
create or replace function raw_to_num(i_raw raw) return number as m_n number; begin dbms_stats.convert_raw_value(i_raw,m_n); return m_n; end; / select column_name, raw_to_num(low_value) low_val, raw_to_num(high_value) high_val from user_tab_columns where table_name = 'T1' and column_name = 'SKEW' ; COLUMN_NAME LOW_VAL HIGH_VAL -------------------- ---------- ---------- SKEW 1 80
To finish off, you would probably want to query the user_tab_columns (or related) views with a decode() on the data_type to decide which of the functions to use, and then perform an explicit to_char() on the result of the decode(). But that task is left as an exercise for the reader.
Addendum: If you read the comments you will see that some of them have taken up the exercise and supplied some answers.
Update Apr 2020
Oracle has finally added the functions to dbms_stats that I’ve indicated in the notes above; so in 19c (and probably in 18c) the following functions are available:
convert_raw_to_bin_double convert_raw_to_bin_float convert_raw_to_date convert_raw_to_number convert_raw_to_nvarchar convert_raw_to_rowid convert_raw_to_varchar2
THese all take a RAW as an input (which you might generate using the hextoraw() function, and return the type indicated by the function name.
Exercise done.- reader
Comment by anonymous — November 29, 2006 @ 8:02 pm GMT Nov 29,2006 |
Seems funny that Oracle should put these procedures in the DBMS_STATS package when the UTL_RAW package has a bunch of casting functions for RAW values (CAST_TO_BINARY_DOUBLE, CAST_TO_BINARY_FLOAT, CAST_TO_BINARY_INTEGER, CAST_TO_NUMBER, CAST_TO_NVARCHAR2, CAST_TO_VARCHAR2). Note the absence of a CAST_TO_DATE function.
Cheers
Tim…
Comment by Tim Hall — November 30, 2006 @ 8:01 am GMT Nov 30,2006 |
We have found out dependence of LOW_VALUE, HIGH_VALUE from parameters NLS_COMP, NLS_SORT. However DBMS_STATS documentation is not present the description of such behaviour…
Comment by Pavel Kozlov — June 7, 2007 @ 8:10 am BST Jun 7,2007 |
I am attempting to change the statistics value of high_value with the help of dbms_stats.set_column_stats. For some reason I struggle to find a function to convert date to raw. Am I looking in the wrong place or am I missing something?
Comment by Jan Rod — August 24, 2009 @ 7:13 pm BST Aug 24,2009 |
Jan,
you don’t have to convert DATE to RAW when setting low/high value. Just let the dbms_stats.prepare_column_stats do the dirty work for you. I hope there are no bug in my EXAMPLE :)
Comment by Pavol Babel — August 24, 2009 @ 8:42 pm BST Aug 24,2009 |
Can you please tel me what > is used for and how ? what do i enter when i get prompt ? thanks
Comment by Jim — January 20, 2012 @ 8:47 pm GMT Jan 20,2012 |
This is a side effect of wordpress and it’s handling of the “greater than” sign. In some cases it comes out as “>”. I’ve fixed it in the example above.
Comment by Jonathan Lewis — January 21, 2012 @ 5:04 pm GMT Jan 21,2012
thanx jonathan for repairing my example. As far I can remember it had been written before wordpress started to support sourcecode tag (so formating was poor). You have obviously fixed it layter, but > remained :) Now it seems to be 100% correct.
Comment by Pavol Babel — January 21, 2012 @ 10:57 pm GMT Jan 21,2012
BTW, you could set the RAW value directly into srec.maxval . But you have to write your own RAW TO DATE function.
RAW representation of DATE in user_tab_columns follows the OCI 7BYTE representation of DATE. You can read the OCI Docmuentation to understand it.
If you convert each number to HEXA and concat them, you’ll get RAW from low/high_val from user_tab_columns/user_tab_col_statistics
Comment by Pavol Babel — August 24, 2009 @ 8:56 pm BST Aug 24,2009 |
http://marogel.wordpress.com/2013/04/29/utl_raw-cast_to_date/
shows an implementation
Comment by Matthias Rogel — April 29, 2013 @ 2:02 pm BST Apr 29,2013 |
I am having problem setting the high value. Does it have to do with histograms already being set ? How can i set it then, i f that is the case. My rec_srec.epic value is 253
Thanks
Comment by Jim — June 10, 2014 @ 9:46 pm BST Jun 10,2014 |
Jim,
If you’re using the sample in an earlier comment to set the high value then the pre-existence of a histogram probably is your problem. Since your rec_srec.epc = 253 you can modify the code by:
a) remove the if .. end if check on rec_srec.epc
b) add a line after the “datevals :=” line setting rec_srec.epc:= 2;
The epc (end point count) is the number of elements in the array, if the value doesn’t match the actual array you get an error whose number I forget.
For further examples on using set_column_stats see: https://jonathanlewis.wordpress.com/2010/03/23/fake-histograms/
Comment by Jonathan Lewis — June 11, 2014 @ 10:14 am BST Jun 11,2014 |
Hi Jonathan
thanks very much for getting back to me
i implemented the change but here is my question and what I am trying to accomplish
That worked great by the way
I generaly gather column stats on the “CreateDate” column of my “DTree” table to get the high value for CreateDate
begin
dbms_stats.gather_table_stats(
ownname=> ‘LLPROD’,
tabname=> ‘DTREE’ ,
estimate_percent=> DBMS_STATS.AUTO_SAMPLE_SIZE,
cascade=> DBMS_STATS.AUTO_CASCADE,
degree=> null,
no_invalidate=> DBMS_STATS.AUTO_INVALIDATE,
granularity=> ‘AUTO’,
method_opt=> ‘FOR COLUMNS CREATEDATE SIZE 254’);
end;
/
Checking, I get 254 buckets from user_tab_col_statistics
But what I find is that I do not usually get the Highest value for CreateDate. probably because of sampling. I am guessing
Using your script with the mods you just sent me
I am setting the High Value for CreateDate to SYSDATE for the table
I now see the buckets are getting reset to 1
and the CreateDate does have the SYSDATE value
My question is do I have to be concerned that the Buckets are now 1 ?
What happens when the stats are collected by Oracle Enterprise Manager (10g) ?
Does the High Value get re-valued ?
Appreciate Your Help
Jim
Comment by Jim — June 16, 2014 @ 8:08 pm BST Jun 16,2014 |
Jim,
So what you’re after is code to replace the current highest value in the histogram with a value you select while leaving the histogram intact. (I’d be inclined to run my own code to generate the whole histogram, but that might be duplicating too much run-time resource usage if can’t change the code that’s already there to gather the histogram).
I don’t think I’ve tried this before – so subject to testing and I may blog it some time over the next couple of weeks – but I think you could include a loop in the pl/sql to populate the date array and the bucket array – then putting in your high value on the last date array entry. You probably need to consider variations for frequency and height-balanced histograms, and the query for the bucket array might require you to use an analytic function to find differences between endpoint values.
Something like:
Comment by Jonathan Lewis — June 17, 2014 @ 7:48 am BST Jun 17,2014 |
Hi Jonathan
I may now be getting way over my head with this new code
I am just trying to ensure that the highest value of the CREATEDATE column for the table DTREE is todays date
after i collect stats on the column:
If I run the previous code I get the sysdate value but I only now have 1 bucket instead of 254
Trying to implement your code is a bit overwhelming for me
as I am not a pl/sql expert so I am getting errors tring to incorporate
I am not sure what you meant by thee lines
Any assitance is appreciated
Jim
Comment by Jim — June 17, 2014 @ 7:03 pm BST Jun 17,2014 |
Jim,
Sorry, I’d assumed you were proficient in PL/SQL.
I’ll see if I can find an odd half hour some time later this week to write up an example as a new blog item. It may have to wait until I’m on the plane to Seattle for Kaleidoscope, though.
Comment by Jonathan Lewis — June 18, 2014 @ 5:56 am BST Jun 18,2014 |
JL,
I wish I was .. I am self taught and I learn as I go. Appreciate when folks like you help out
I wil keep tring to figure it out though
Jim
Comment by Jim — June 18, 2014 @ 10:52 pm BST Jun 18,2014 |
Hi Jonathan
I found some code (not mine) I implemented to get past the error I was getting and I am pretty confident that I am getting the results I need, but I cannot seem to get figure out the next step which is updating that last record in the histogram table.
Here is what I came up with thanks to your input and Mr. Rajeshwaran at http://rajeshwaranbtech.blogspot.com/2011/01/histograms-on-date-varchar-and-numeric.html
tested the code in a select statment::
Thanks
jim
Comment by Jim — July 2, 2014 @ 8:18 pm BST Jul 2,2014
Jim,
I wrote up an example of how to do this a few days ago, but forgot to publish it. There are a couple of little traps in the method I’ve used (which is just a quick and dirty, so there may be a smarter method). I’ll copy the whole demo script to the blog in a couple of minutes.
Comment by Jonathan Lewis — July 4, 2014 @ 8:21 pm BST Jul 4,2014
[…] is a quick response to a question on an old blog post asking how you can adjust the high value if you’ve already got a height-balanced histogram […]
Pingback by Adjusting Histograms | Oracle Scratchpad — July 4, 2014 @ 8:32 pm BST Jul 4,2014 |
Hi Jonathan
will take a look at the code you wrote
really appreciate your time in this matter
Thanks
Jim
Comment by Jim — July 7, 2014 @ 4:17 pm BST Jul 7,2014 |
With any luck I have formatted this properly …
While fooling around with user_tab_col_statistics I found that as already noted the UTL_RAW package works just fine for decoding the values when they are numeric or character values.
Dates however are not so straight forward.
Also as noted, a function can be created use the dbms_stats procedures
However it is not always convenient or possible to create a function, and some “straight” SQL would be nice.
‘Straight’ as in no PL/SQL is required (that only works in 12c+) but nonetheless is somewhat convoluted.
But, it does work for dates.
I haven’t tried timestamps, maybe someone else can take a stab at that.
Here’s an example that worked on 11.2.0.2
The internal format of oracle dates as stored in the database are well documented if you google a bit.
Results:
Comment by jkstill — December 8, 2015 @ 3:40 am GMT Dec 8,2015 |
[…] years ago I wrote a note with some comments about conveting the low_value and high_value columns of user_tab_columns to see […]
Pingback by raw timestamp | Oracle Scratchpad — April 10, 2020 @ 6:59 pm BST Apr 10,2020 |
[…] values from DBA_TAB_COL_STATISTICS’ HIGH_VALUE and LOW_VALUE. Here are two good examples from Jonathan Lewis and Martin […]
Pingback by Decode HIGH_VALUE and LOW_VALUE, including TIMESTAMP data types | EDUARDO CLARO — November 4, 2021 @ 5:41 pm GMT Nov 4,2021 |