Home>Question Details



Getachew -- Thanks for the question regarding "Making Oracle Case insensitive ", version 9.2.0.4

Submitted on 12-Mar-2004 11:57 Central time zone
Last updated 22-May-2007 9:26

You Asked

Tom:
    First and foremost, thank you for the great work you do for
the Oracle community.

My question is:

- We have a third party application we use for selecting specific
values from several tables. The character values stored in a field could be in any of the 
following formats:
"Bell", "bell" , "BELL" , "beLL" etc..
1) Is there a way to force (change) values (either to UPPER or Lower case) during a DML 
other than using triggers?  
if not,
2) Is there a way to force a select query (other than using functions UPPER or LOWER) to 
return all the values regardless of the case that a user enters? 

Thank you. 

and we said...

1) no

2) in 10g, yes.

ops$tkyte@ORA10G> create table t ( data varchar2(20) );
 
Table created.
 
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> insert into t values ( 'Hello' );
 
1 row created.
 
ops$tkyte@ORA10G> insert into t values ( 'HeLlO' );
 
1 row created.
 
ops$tkyte@ORA10G> insert into t values ( 'HELLO' );
 
1 row created.
 
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> create index t_idx on
  2  t( nlssort( data, 'NLS_SORT=BINARY_CI' ) );
 
Index created.
 
ops$tkyte@ORA10G> pause
 
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> variable x varchar2(25)
ops$tkyte@ORA10G> exec :x := 'hello';
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> select * from t where data = :x;
 
no rows selected
 
ops$tkyte@ORA10G> pause
 
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> alter session set nls_comp=ansi;
 
Session altered.
 
ops$tkyte@ORA10G> alter session set nls_sort=binary_ci;
 
Session altered.
 
ops$tkyte@ORA10G> select * from t where data = :x;
 
DATA
--------------------
Hello
HeLlO
HELLO
 
ops$tkyte@ORA10G> pause
 
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> set autotrace on
ops$tkyte@ORA10G> select /*+ first_rows */ * from t where data = :x;
 
DATA
--------------------
Hello
HeLlO
HELLO
 
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=2 Card=1 Bytes=12)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T' (TABLE) (Cost=2 Card=1 Bytes=12)
   2    1     INDEX (RANGE SCAN) OF 'T_IDX' (INDEX) (Cost=1 Card=1)
 

Reviews    
5 stars Making Oracle Case insensitive   March 13, 2004 - 9pm Central time zone
Reviewer: Getachew G. from Minneapolis, MN USA
Thank you again.

I will test and implement this in 10G in a few months.
I am not sure what the impact will be if I set the 
two parameters(nls_comp and nls_sort) at the system
level.  But, thank you for providing me with a good information. 


Followup   March 14, 2004 - 9am Central time zone:

it'll make everything case insensitive will be the impact.  Not sure I'd do it system wide, but via 
alter sessions in the app or via an on logon trigger -- sure. 

4 stars no caveat ?!   March 14, 2004 - 2pm Central time zone
Reviewer: Gabe 
Regarding #2 and the answer "in 10g, yes" ...

My observations/questions:
1. I'm assuming statistics were gathered automatically (10g feature)
2. Is RBO still available in 10g?
3. I know Cardinality is an estimation ... but why wouldn't the optimizer estimate on the side of 
caution with "Card=<#rows in table>" (or some function of it) rather than "Card=1"?
4. What was the point of first_rows? For the method to be deterministic, the FBI has to be used 
(hints are just ... hints). In fact, any query against a table with 3 rows should probably result 
in a FT ... here the FT would translate in a bug in the application.

I'm highly suspicious of relying on indexes for business logic when querying Oracle (for DML? ... 
yes, FTIs are very useful as you show in your last book) ... is my suspicion unfounded? Can Oracle 
really be forced to always use an index (FBI or not)?

Thanks.

 


Followup   March 14, 2004 - 2pm Central time zone:

1) no, there weren't any 

2) yes, but not supported and not by default

3) small table.  forced the cbo to guess with the hint so the index would be used.

4) to bias the index, table was too small to use an index "for real" otherwise. I was trying to 
demonstrate that "yes, this case insensitive stuff can be as efficient as case sensitive, given the 
correct indexes are in place"

I'm not relying on the index for anything here.  I was merely demonstrating that the index can in 
fact be used transparently.

ops$tkyte@ORA10G> select /*+ FULL(t) */ * from t where data = :x;
 
DATA
--------------------
Hello
HeLlO
HELLO
 
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=1 Bytes=12)
   1    0   TABLE ACCESS (FULL) OF 'T' (TABLE) (Cost=3 Card=1 Bytes=12)


Full scans work just as well.  I would never suggest on relying on a query plan for getting data 
"just so".  Either plan works the same (although they could return the data in very different order 
of course! but if you need a certain order, that is what order by is all about) 

5 stars indeed ...   March 14, 2004 - 3pm Central time zone
Reviewer: Gabe 
"I'm not relying on the index for anything here"
I can see now you don't.

So it is all about these:
  alter session set nls_comp=ansi;  --works in 9i
  alter session set nls_sort=binary_ci;

Guess the "binary_ci" is the thing that makes this a 10g solution only. I'll look it up in the 
docs.

Thanks. 


Followup   March 14, 2004 - 7pm Central time zone:

binary_CaseInsensitive
       ^   ^

 

5 stars   March 14, 2004 - 11pm Central time zone
Reviewer: Bhagat Singh from India
Hello Tom,
may be most of the peoply might not be having 10g right now but I was astonished to see the answer, 
I was expecting some function based indexes and all any special reason for this.

regards
Bhagat Singh 


Followup   March 15, 2004 - 7am Central time zone:

curious -- you did see a function based index:

ops$tkyte@ORA10G> create index t_idx on
  2  t( nlssort( data, 'NLS_SORT=BINARY_CI' ) );


but any special reason for what exactly? 

4 stars LIKE operator for case-insensitive queries   March 15, 2004 - 5pm Central time zone
Reviewer: Gary from Sydney, Australia
Haven't got 10g, so cannot verify this, but it has been reported on another website
(
http://www.quest-pipelines.com/pipelines/dba/index.asp
, that while = (and presumably <, > etc) all pick up on this case-insensitive setting, the LIKE 
operator does not.

Also changing the nls_sort parameter means you cannot mix case-sensitive and case-insensitive 
predicates in a query.
This means you have a choice of 
1) Have both case-sensitive and case-insensitive indexes
2) Risk some queries not have the correct sensitivity index available on some predicates 
3) Choose whether the database as a whole should be case-sensitive or insensitive, and design your 
indexes accordingly

Personally, I still prefer the 'old-tech' UPPER(col)='...' with a function based index on the 
UPPER(col).
That allows the case-insensitivity to be applied at the lowest level so has more flexibility. 
For example, with a table with Address, City, State and Zip Code, you could decide to be 
case-insensitve for Address, but case-sensitive for state because you store them all in upper case.

 


Followup   March 15, 2004 - 6pm Central time zone:

correct but an Oracle Text index can (even in 9i, 8i) do that.


 

3 stars non 10g solution   July 9, 2004 - 7am Central time zone
Reviewer: Dez from Netherlands
Recently I encountered the same problem and we couldnt use Function Based Indexes or ad an extra 
index. The way Oracle Forms translates Queries on Case Insensitive fields gives another option:

select * from t where lower(data)='hello' and (data like 'h%' or data like 'H%')

This way the query will still run alot faster without using Funtion Based Index

Hopefully it will be usefull.

 


4 stars an approach for oracle 9   August 12, 2004 - 2pm Central time zone
Reviewer: Henry Rabinowitz from New York, NY
I read in the oracle 9 documentation that one can get case insensitive comparison by saying
  alter session set NLS_COMP=ANSI;
  alter session set NLS_SORT=GENERIC_BASELETTER;
This does appear to work for queries like
  select * from emp where ename = 'miller'
But it does not appear to work with queries using LIKE, such as
  select * from emp where ename like 'mill%'
 


5 stars This does not work for LIKE operators   August 13, 2004 - 12pm Central time zone
Reviewer: Nags from Boston
When doing case insensitive searches, the parameters for 9i work, but we cannot use LIKE operators. 
 How to make it work ?

These are the parameters that we are using..

alter session set nls_comp=ansi;
alter session set nls_sort=GENERIC_BASELETTER; 


Followup   August 13, 2004 - 5pm Central time zone:

they do not work with like, even in 10g --  

5 stars Our application is totally case insensitive   August 13, 2004 - 12pm Central time zone
Reviewer: Nags from Boston
I forgot to mention.. our application is totally case insensitive.  That means we always do case 
insensitive searches. 


Followup   August 13, 2004 - 5pm Central time zone:

oracle text is totally case insensitive as well -- you might consider using the power of that - it 
can do tons more than "like" 

5 stars Case sensitivity an issue for our application   August 14, 2004 - 12am Central time zone
Reviewer: Nags from Boston
Please let me explain the issue we have, and I would really appreciate if you can help me.

Our application is web based and has been designed to work with both Oracle and SQL Server.  It is 
a licensing system.

The entire application logic and processing of data is being done in the application.  (This design 
is not under my control)  We use no procedures, functions, triggers etc.  Some how I forced my 
management to use unique constraints, referential integrity.  We have all columns as NVARCHAR2 & 
NTEXT.  When doing searches, for eg. COMPANY_NAME, we added a shadow column, which the application 
makes sure that it keeps it up to date.  For all other searches, we do have indexes on the 
necessary columns, but all are case insensitive searches (on SQL Server)  We do not use UPPER 
function at all.

If we have to search for First name, last name, and in the admin section configure the drop downs 
for country, provinces etc.  When we switched to oracle, all the searches started failing.  I 
didn't make sense for us to tell the user that the searches are case sensitive, because the user 
does not care. 

Can I still have a work around in doing case insensitive searches.  I cannot use oracle text 
because my management thinks that dba should have very little knowledge or no knowledge of the 
database to install our product.

 


Followup   August 14, 2004 - 1pm Central time zone:

<quote>
Our application is web based and has been designed to work with both Oracle and 
SQL Server.  It is a licensing system.
</quote>

ugh.


can you tell me the name of this product, so I can avoid it, it'll work maybe OK on a single 
database, horribly on the other.  no matter which one, it will not exploit any feature of a big 
piece of software companies pay money for and expect to be used.

(the best was to be database "flexible" -- use only stored procedures, outlaw 
insert/update/delete/select in the code outside of the database. use the database to death)



Apparently you didn't design to work with both Oracle and SQLServer.  Your second to last paragraph 
"proves that".

Sorry, Oracle <> SQLServer (and it goes the other way as well, there are thousands of things we do 
that they do not).  database independence, the holy grail.  I lol everytime I see it.  what a waste 
of good money.  I'd rather see you pick one or the other database here and just *use it*.

Wonder how you work in a multiuser situation, given that our locking models are as orthogonal as 
you can get.  Love to look at some of your code, I'm sure I could break every single business rule 
you *think* you are enforcing in the client and really mess up your data integrity :)

 

5 stars Case sensitivity an issue for our application   August 14, 2004 - 1pm Central time zone
Reviewer: Nags from Boston
I totally agree to all the issues that you put forth.  Its not my decision, my CTO decides it.  We 
did have a lot of data integrity issues, but his argument is 

"is we add restrictions on the database it would be difficult if the restriction changes for a 
different client"

Our application is entirely based on some configuration tables.

Our application was first designed for Oracle only.  But when oracle became expensive (about 1 
million to own) about 3 years  back my CTO decided to make our application portable to both oracle 
and sql server.   And finally our application became more oracle less sql server.

We had lot of issues with multiuser and locking.  And a lot of performance issues. I am trying to 
work with the parameters I have.

Is there an alternative in oracle for case insensitive searches or we just have to live with it ? 


Followup   August 14, 2004 - 2pm Central time zone:

CTO in this case means "chief 'totally not clued in' officer"?  What is a "C" level person doing 
making nitty gritty technical decisions that should be engineering level decisions.  oh well.  I 
won't get started.


Expensive?  We cost less than SQLServer given the amount of functionality you are using (eg: none). 
 Oacle Standard Edition is cheaper than SQL server.  I think your CTO read a magazine maybe.

1 million would be a non-discounted 50 cpu license.  Your application runs on a 50 cpu machine 
(nah, nix that, you are running on windows).  I just went to store.oracle.com and ordered me 5 
named users for $1,500 -- upgraded to $1,830 to get all software updates and complete support.

Use the shadow column trick everywhere
or 
start using the database -- function based indexes for example.


 

5 stars Case sensitivity an issue for our application   August 14, 2004 - 2pm Central time zone
Reviewer: Nags from Boston
Thanks a lot for your help.

I was talking about Oracle being expensive about 3 years back.  Not now.  Moreover ours is a 
webbased application, hence we could not use named user license.

Based on your suggestion, we will surely revisit the application.
 


Followup   August 14, 2004 - 4pm Central time zone:

we haven't changed pricing drastically in eons.  We went from power units to "just by cpu" many 
many years ago.  

Really, its been that way for a long long time.  in 2001, it cost no less, no more.  And definitely 
not the orders of magnitude you quote.

Even by cpu, you'll find it way comparable with sqlserver. 

5 stars Setting case insensitive negates indexes ??   October 19, 2004 - 5pm Central time zone
Reviewer: Anton from NZ
Hi Tom.

If I set an Oracle 9iR2 database to be case insensitive ie.

alter session set nls_comp=ansi;
alter session set nls_sort=GENERIC_BASELETTER; 


And I have an index on say a name column, will the above setting always cause Oracle to do a full 
table scan and not use the index ?

Thanks 


4 stars sorting on column by number + upper of that   April 13, 2005 - 12pm Central time zone
Reviewer: Jelena from Germany
Hi Tom, 
I have two questions about sorting. 

Application generates sql and sorting clauses dynamically and usually we get something like:

select a, b, c 
from abc_table
order by 3

Now i want to make it order by case-insensitive-on-3rd-col and i did:

select a, b, c 
from abc_table
order by upper(3) 

but it doesn't work. Is it really applying upper to number 3 and then sorting on nothing??? as it 
seems not to sort at all. (with upper(c) it works, but it's difficult to change application)

And second question, to make it work more intelligent way, i wanted to alter database not session, 
but it looks as I can only change nls_sort in pfile and need to restart database. As this is 24x7 
system, it's not easy, so is there any option like alter system... or alter database set nls_sort, 
without restart? 

Thank you, 
Jelena 


Followup   April 13, 2005 - 12pm Central time zone:

it would be sorting on the upper(literal)....

sorry, but in order to sort on the UPPER of column 3, column 3 would have to be uppercased.

but what version?  

you can change the nls_sort in a session via alter session without restarting. 

4 stars NLS_COMP   February 2, 2006 - 2pm Central time zone
Reviewer: Deepak Haldiya from FL, USA
Hi Tom,

1. I read in this thread that LIKE operator does not work with case insensitive searches.
I tried the following 

alter session set nls_comp=ansi;
alter session set nls_sort=binary_ci ;
SQL> select * from t where data like :x || '%' ;
DATA
--------------------
Hello
HeLlO
HELLO

Correct me if i am wrong in my understanding, but it seems that LIKE works fine, just like =,<,> 
etc.

2. What's the importance of this statement:
alter session set nls_comp=ansi;

The default nls_comp is binary. The nls_sort=binary_ci does not work fine nls_comp=binary. Aren't 
we doing a binary case insensitive comparison here?

Thanks
Deepak
 
   


 


Followup   February 2, 2006 - 2pm Central time zone:

you don't show us what you set :x to, I suspect 'H'.... (and they are all like H% - without CI 
processing...)


But look:

ops$tkyte@ORA10GR2> create table t ( data varchar2(20) );

Table created.

ops$tkyte@ORA10GR2> insert into t values ( 'Hello' );

1 row created.

ops$tkyte@ORA10GR2> insert into t values ( 'HeLlO' );

1 row created.

ops$tkyte@ORA10GR2> insert into t values ( 'HELLO' );

1 row created.

ops$tkyte@ORA10GR2>
ops$tkyte@ORA10GR2> variable x varchar2(20)
ops$tkyte@ORA10GR2> exec :x := 'hello';

PL/SQL procedure successfully completed.

ops$tkyte@ORA10GR2> alter session set nls_comp=ansi;

Session altered.

ops$tkyte@ORA10GR2> alter session set nls_sort=binary_ci;

Session altered.

ops$tkyte@ORA10GR2> select * from t where data = :x;

DATA
--------------------
Hello
HeLlO
HELLO

ops$tkyte@ORA10GR2> select * from t where data like :x||'%';

no rows selected

ops$tkyte@ORA10GR2> select * from t where upper(data) like Upper(:x||'%');

DATA
--------------------
Hello
HeLlO
HELLO

 

5 stars LIKE operator Works !!!   February 2, 2006 - 3pm Central time zone
Reviewer: Deepak Haldiya from FL, USA
Hi Tom,

if you set 

alter session set nls_comp=linguistic ;

LIKE OPERATOR in the WHERE CLAUSE for case insensitive comparison works. (i forgot to replace ansi 
with linguistic in my previous post).

drop table t ;
create table t ( data varchar2(20) );
insert into t values ( 'Hello' );
insert into t values ( 'HeLlO' );
insert into t values ( 'HELLO' );

alter session set nls_comp=linguistic ;
alter session set nls_sort=binary_ci;

variable x varchar2(25)
exec :x := 'hello';

SQL> select * from t where data like :x;

DATA
--------------------
Hello
HeLlO
HELLO

SQL> select * from t where data like :x || '%';

DATA
--------------------
Hello
HeLlO
HELLO

SQL> select * from t where data = :x ;

DATA
--------------------
Hello
HeLlO
HELLO

For NLS_SORT=ANSI option, Oracle Manual says : A setting of ANSI is for backwards compatibility; in 
general, you should set NLS_COMP to LINGUISTIC.


Tom, could you please elaborate on what does NSL_COMP=BINARY option do? This is the defualt setting 
set by Oracle.

Thanks
Deepak

 


Followup   February 3, 2006 - 1pm Central time zone:

binary is just that - binary, bits and bytes binary.  bytes sort byte by byte.


Thanks for the followup, this is the new thing I picked up today myself. 

5 stars LIKE operator Works !!!   February 8, 2006 - 7am Central time zone
Reviewer: Madhusudan from Pune,India
Thanks Tom & Deepak for very good solution..
Presently working on sqlserver conversion ..
I want to make queries case insensitive...
My boss do not want changes in query so he opted for nls_sort/nls_comp approach

One approach is to use of on logon trigger..
Second approach is to put it in spfile so it will be globally applicable.
I had two queries..

1. 
Personally i feel 1st approach will be better as there will be control as i can make it user based 
case insensitive. 
 DECLARE
   p_user  VARCHAR2(50);
 begin
     execute immediate
         'alter session set nls_date_format = ''DD-MM-YYYY'' ';
   SELECT user
   INTO p_user
   FROM dual;
   IF p_user='SA' THEN
     execute immediate
         'alter session set nls_sort = BINARY_CI';
     execute immediate
         'alter session set nls_comp = linguistic ';
   END IF;

 end;

2.
while putting in spfile i had crated spfile added parameters. But there is problem though it shows 
correct parameters it's not behaving as expected. Please advice.

SQL*Plus: Release 10.1.0.2.0 - Production on Wed Feb 8 16:52:07 2006

Copyright (c) 1982, 2004, Oracle.  All rights reserved.

Connected to:

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

sys@DIAMOND> show parameter nls_sort
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
nls_sort                             string      BINARY_CI
sys@DIAMOND> show parameter nls_comp

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

nls_comp                             string      linguistic

sys@DIAMOND> ed
Wrote file afiedt.buf

  1  select ISDEFAULT  ,ISSES_MODIFIABLE, ISSYS_MODIFIABLE       ,ISINSTANCE_MODIFIABLE

  2*   , ISMODIFIED     ,ISADJUSTED     , ISDEPRECATED   from v$PARAMETER where name='nls_sort'

  3  /

ISDEFAULT ISSES ISSYS_MOD ISINS ISMODIFIED ISADJ ISDEP

--------- ----- --------- ----- ---------- ----- -----

FALSE     TRUE  FALSE     FALSE FALSE      FALSE FALSE

 

sys@DIAMOND> conn scott/tiger@diamond

Connected.

scott@DIAMOND> select * from t_case where ename like 'king';

ENAME

----------

king

 

scott@DIAMOND> alter session set nls_sort=BINARY_CI;
Session altered.

scott@DIAMOND> select * from t_case where ename like 'king';

ENAME
----------
KING
King
king



Please guide me.. 


Followup   February 8, 2006 - 8am Central time zone:

http://asktom.oracle.com/~tkyte/Misc/NLSDateFormat.html
that is the reason the init.ora isn't working - the client has some NLS parameter set, hence all 
default, the trigger is the correct approach (or in the application itself) 

5 stars Use regular expressions instead of 'LIKE' for case-insensitivity   February 8, 2006 - 12pm Central time zone
Reviewer: Stewart W. Bryson from Atlanta, GA
The 'i' match parameter tells Oracle to be case-insensitive.

Indexes won't be used for REGEXP_LIKE, though.

SQL> create table t ( data varchar2(20) );

Table created.

Elapsed: 00:00:00.28
SQL> insert into t values ( 'Hello' );

1 row created.

Elapsed: 00:00:00.01
SQL> insert into t values ( 'HeLlO' );

1 row created.

Elapsed: 00:00:00.01
SQL> insert into t values ( 'HELLO' );

1 row created.

Elapsed: 00:00:00.00
SQL> select * from t where regexp_like(data,'hel','i');

DATA
--------------------
Hello
HeLlO
HELLO

3 rows selected.

Elapsed: 00:00:00.02
SQL>  


4 stars Performance Issues   February 28, 2006 - 2pm Central time zone
Reviewer: Yogesh from Pune, India
Need your opinion … Weather we should be using case insensitive feature, specifically when we are 
dealing with high performance sensitive queries and TB size databases? 

 


Followup   March 1, 2006 - 7am Central time zone:

It is just a collating character set.  Anytime you use anything other than binary you are sort of 
doing this already. 

5 stars Oracle Text and Case Sensitivity   May 10, 2007 - 7pm Central time zone
Reviewer: A reader 
I understand that Oracle Text index allows case insensitive search. Is there any way we can make the query either case sensitive or case insensitive on demand?

Followup   May 11, 2007 - 11am Central time zone:

that is decided when you create the index, if you use the default, it is all folded to a consistent case in the supporting data structures (eg; the case is "lost")
5 stars   May 11, 2007 - 1pm Central time zone
Reviewer: A reader 
What then is the best way to handle the following situation?

SELECT ... WHERE CONTAINS(col1, 'abc') > 0

and

-- exact match
SELECT ... WHERE col1 = 'aBc'



Followup   May 11, 2007 - 3pm Central time zone:

what you just did?

however, if you are using 10g, and you really have a "single word" in there, then you can use case insensitive session settings.


ops$tkyte%ORA10GR2> create table t ( data varchar2(20) );

Table created.

ops$tkyte%ORA10GR2> insert into t values ( 'Hello' );

1 row created.

ops$tkyte%ORA10GR2> insert into t values ( 'HeLlO' );

1 row created.

ops$tkyte%ORA10GR2> insert into t values ( 'HELLO' );

1 row created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> create index t_idx_ci on t( nlssort( data, 'NLS_SORT=BINARY_CI' ) );

Index created.

ops$tkyte%ORA10GR2> create index t_idx    on t( data );

Index created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2>ops$tkyte%ORA10GR2> variable x varchar2(25)
ops$tkyte%ORA10GR2> exec :x := 'Hello';

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> set autotrace on explain
ops$tkyte%ORA10GR2> select /*+ first_rows */ * from t where data = :x;

DATA
--------------------
Hello


Execution Plan
----------------------------------------------------------
Plan hash value: 2946670127

--------------------------------------------------------------------------
| Id  | Operation        | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT |       |     1 |    12 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| T_IDX |     1 |    12 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("DATA"=:X)

Note
-----
   - dynamic sampling used for this statement


ops$tkyte%ORA10GR2> alter session set nls_comp=ansi;

Session altered.

ops$tkyte%ORA10GR2> alter session set nls_sort=binary_ci;

Session altered.

ops$tkyte%ORA10GR2> select /*+ first_rows */ * from t where data = :x;

DATA
--------------------
Hello
HeLlO
HELLO


Execution Plan
----------------------------------------------------------
Plan hash value: 164467589

----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |     1 |    12 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T        |     1 |    12 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_IDX_CI |     1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access(NLSSORT("DATA",'nls_sort=''BINARY_CI''')=NLSSORT(:X,'nls_sort=''BI
              NARY_CI'''))

Note
-----
   - dynamic sampling used for this statement


5 stars   May 12, 2007 - 12pm Central time zone
Reviewer: A reader 
So when I execute a case sensitive query, I turn off the setting, and turn it back on when I execute a case insensitive query? Would this work in an application that uses connection pooling?

Also would this work well if I have a case insensitive query that has wildcard at both ends of the predicate?

select /*+ first_rows */ * from t where data = '%' || :x || '%';




Followup   May 14, 2007 - 1pm Central time zone:

if you turn it on and off - sure it would work in a connection pool, you would just need to always set it to what you wanted.

if you use LINGUISTIC comparison semantics, like will work (you meant like I think...)

ops$tkyte%ORA10GR2> alter session set nls_comp=LINGUISTIC ;

Session altered.

ops$tkyte%ORA10GR2> alter session set nls_sort=binary_ci;

Session altered.

ops$tkyte%ORA10GR2> select * from t where data like '%'||:x||'%';

DATA
--------------------
Hello
HeLlO
HELLO

ops$tkyte%ORA10GR2> select * from t where data = :x;

DATA
--------------------
Hello
HeLlO
HELLO



5 stars   May 14, 2007 - 2pm Central time zone
Reviewer: A reader 
If my application needs to support all the following operators, some case sensitive, some case insensitive, would Oracle Text index be the best solution since the Text index supports both case insensitive and wildcard searches very well?


UPPER (<column>) LIKE '%ABC%'
UPPER(<column>) NOT LIKE '%ABC%'
<column> = 'abc'
<column> <> 'abc'
UPPER(<column>) = 'ABC'
UPPER(<column>) LIKE 'ABC%'
UPPER(<column>) LIKE '%ABC'
UPPER(<column>) IN ('ABC', 'DEF', 'XYZ')
UPPER(<column>) NOT IN ('ABC', 'DEF')



Followup   May 14, 2007 - 5pm Central time zone:

all but the "like" with leading '%' would be best served via conventional b*tree indexing.

at which point, a text index might be best (leading wildcard)
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:37336026927381#37360199308431


"not" typically will "not" use an index, most of the results are "not" like that.
4 stars Oracle 9i: - Case Insensitive Query problem   May 22, 2007 - 1am Central time zone
Reviewer: cPiyush from IND
Hi Tom,

I have read your followups on this topic.
I have certain constraints: -
1. I can not change my queries(so can't use UPPER(<col>)..)

2. This looks wonderful
    alter session set nls_comp=ansi;
    alter session set nls_sort=binary_ci;
  But 9i doesn't support 'binary_ci' value.

3. I tried this: -
  alter session set nls_comp=ansi;
  alter session set nls_sort=GENERIC_BASELETTER;
  But this doesn't work for LIKE operator.

Please tell me the best solution considering constraint#1.

Info: - I have to fire case-insensitive queries on table which contains more than 3,000,000 records. & has this structure:
    create table tabName (sno number,
                  col1 varchar2(200),
                  col2 varchar2(200),
                  col3 varchar2(200));

Regards,
cPiyush.

Followup   May 22, 2007 - 9am Central time zone:

upgrade to 10g.

or - use a view?
4 stars Oracle 9i: -CASE INSENSITIVITY   May 25, 2007 - 2am Central time zone
Reviewer: cPiyush from IND
Hmmm...

Even if I will use a view then I will have to change all my queries which are currently selecting from <table> & I will have to make them to select from <view>.

I think I will have to upgrade to 10g.

No other choice remains, as other options are making me more complex.

But I am thinking abt one thing that if setting
  alter session set nls_comp=ansi;
  alter session set nls_sort=GENERIC_BASELETTER;
works for 'equals to' to make case insensitive then why they didn't make it for 'like'(Basically this is also a 'itrative equals to').

Regards,
cPiyush.

5 stars What statistics should replace 'first_rows' hint?   May 8, 2008 - 7am Central time zone
Reviewer: A reader from England
I am using Oracle 10.2.0.1

I wanted to repeat your example, but using optimizer statistics rather than the 'first_rows' hint. I don't seem to have the statistics right, as the index isn't being used:

SQL> create table t ( data varchar2(20) );

Table created.

SQL> insert into t
  2  select 'Current' from all_objects;

41052 rows created.

SQL> 
SQL> insert into t
  2  select 'Historical' from dual;

1 row created.

SQL> 
SQL> 
SQL> create index t_idx on
  2  t( nlssort( data, 'NLS_SORT=BINARY_CI' ) );

Index created.

SQL> 
SQL> 
SQL> 
SQL> set autotrace traceonly

SQL> alter session set nls_comp=ansi;

Session altered.

SQL> alter session set nls_sort=binary_ci;

Session altered.

SQL> 
SQL> select * from t
  2  where data = 'CURRENT';

41052 rows selected.


Execution Plan
----------------------------------------------------------                                          
                    
Plan hash value: 470836197                                                                          
                    
                                                                                                    
                    
-------------------------------------------------------------------------------------               
                    
| Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |               
                    
-------------------------------------------------------------------------------------               
                    
|   0 | SELECT STATEMENT            |       |   465 |  5580 |    18   (0)| 00:00:01 |               
                    
|   1 |  TABLE ACCESS BY INDEX ROWID| T     |   465 |  5580 |    18   (0)| 00:00:01 |               
                    
|*  2 |   INDEX RANGE SCAN          | T_IDX |   186 |       |    57   (0)| 00:00:01 |               
                    
-------------------------------------------------------------------------------------               
                                                                                                    
                                       
Predicate Information (identified by operation id):                                                 
                    
---------------------------------------------------                                                 
                    
                                                                                                    
                    
   2 - access(NLSSORT("DATA",'nls_sort=''BINARY_CI''')=HEXTORAW('63757272656E                       
                    
              7400') )                                                                              
                    
                                                                                                    
                    
Note                                                                                                
                    
-----                                                                                               
                    
   - dynamic sampling used for this statement                                                       
                    


Statistics
----------------------------------------------------------                                          
                    
         44  recursive calls                                                                        
                    
          0  db block gets                                                                          
                    
       5738  consistent gets                                                                        
                    
        117  physical reads                                                                         
                    
          0  redo size                                                                              
                    
     553170  bytes sent via SQL*Net to client                                                       
                    
      30477  bytes received via SQL*Net from client                                                 
                    
       2738  SQL*Net roundtrips to/from client                                                      
                    
          0  sorts (memory)                                                                         
                    
          0  sorts (disk)                                                                           
                    
      41052  rows processed                                                                         
                    

SQL> 
SQL> select * from t
  2  where data = 'HISTORICAL';


Execution Plan
----------------------------------------------------------                                          
                    
Plan hash value: 470836197                                                                          
                    
                                                                                                    
                    
-------------------------------------------------------------------------------------               
                    
| Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |               
                    
-------------------------------------------------------------------------------------               
                    
|   0 | SELECT STATEMENT            |       |   465 |  5580 |    18   (0)| 00:00:01 |               
                    
|   1 |  TABLE ACCESS BY INDEX ROWID| T     |   465 |  5580 |    18   (0)| 00:00:01 |               
                    
|*  2 |   INDEX RANGE SCAN          | T_IDX |   186 |       |    57   (0)| 00:00:01 |               
                    
-------------------------------------------------------------------------------------               
                    
                                                                                                    
                    
Predicate Information (identified by operation id):                                                 
                    
---------------------------------------------------                                                 
                    
                                                                                                    
                    
   2 - access(NLSSORT("DATA",'nls_sort=''BINARY_CI''')=HEXTORAW('686973746F72                       
                    
              6963616C00') )                                                                        
                    
                                                                                                    
                    
Note                                                                                                
                    
-----                                                                                               
                    
   - dynamic sampling used for this statement                                                       
                    


Statistics
----------------------------------------------------------                                          
                    
         11  recursive calls                                                                        
                    
          0  db block gets                                                                          
                    
         80  consistent gets                                                                        
                    
          0  physical reads                                                                         
                    
          0  redo size                                                                              
                    
        415  bytes sent via SQL*Net to client                                                       
                    
        381  bytes received via SQL*Net from client                                                 
                    
          2  SQL*Net roundtrips to/from client                                                      
                    
          0  sorts (memory)                                                                         
                    
          0  sorts (disk)                                                                           
                    
          1  rows processed                                                                         
                    
<b>SQL> exec dbms_stats.gather_table_stats('compass',tabname=>'t',cascade=>true,method_opt=>'for 
all columns size 2',estimate_percent=>null)</b>
PL/SQL procedure successfully completed.

SQL> select * from t
  2  where data = 'CURRENT';

41052 rows selected.


Execution Plan
----------------------------------------------------------                                          
                    
Plan hash value: 1601196873                                                                         
                    
                                                                                                    
                    
--------------------------------------------------------------------------                          
                    
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |                          
                    
--------------------------------------------------------------------------                          
                    
|   0 | SELECT STATEMENT  |      | 41052 |   360K|    22  (14)| 00:00:01 |                          
                    
|*  1 |  TABLE ACCESS FULL| T    | 41052 |   360K|    22  (14)| 00:00:01 |                          
                    
--------------------------------------------------------------------------                          
                    
                                                                                                    
                    
Predicate Information (identified by operation id):                                                 
                    
---------------------------------------------------                                                 
                    
                                                                                                    
                    
   1 - filter(NLSSORT("DATA",'nls_sort=''BINARY_CI''')=HEXTORAW('6375727                            
                    
              2656E7400') )                                                                         
                    


Statistics
----------------------------------------------------------                                          
                    
          8  recursive calls                                                                        
                    
          0  db block gets                                                                          
                    
       2823  consistent gets                                                                        
                    
          0  physical reads                                                                         
                    
          0  redo size                                                                              
                    
     553170  bytes sent via SQL*Net to client                                                       
                    
      30477  bytes received via SQL*Net from client                                                 
                    
       2738  SQL*Net roundtrips to/from client                                                      
                    
          0  sorts (memory)                                                                         
                    
          0  sorts (disk)                                                                           
                    
      41052  rows processed                                                                         
                    

SQL> 
SQL> select * from t
  2  where data = 'HISTORICAL';


Execution Plan
----------------------------------------------------------                                          
                    
Plan hash value: 1601196873                                                                         
                    
                                                                                                    
                    
--------------------------------------------------------------------------                          
                    
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |                          
                    
--------------------------------------------------------------------------                          
                    
|   0 | SELECT STATEMENT  |      |     1 |     9 |    22  (14)| 00:00:01 |                          
                    
|*  1 |  TABLE ACCESS FULL| T    |     1 |     9 |    22  (14)| 00:00:01 |                          
                    
--------------------------------------------------------------------------                          
                    
                                                                                                    
                    
Predicate Information (identified by operation id):                                                 
                    
---------------------------------------------------                                                 
                    
                                                                                                    
                    
   1 - filter(NLSSORT("DATA",'nls_sort=''BINARY_CI''')=HEXTORAW('6869737                            
                    
              46F726963616C00') )                                                                   
                    


Statistics
----------------------------------------------------------                                          
                    
          8  recursive calls                                                                        
                    
          0  db block gets                                                                          
                    
         86  consistent gets                                                                        
                    
          0  physical reads                                                                         
                    
          0  redo size                                                                              
                    
        415  bytes sent via SQL*Net to client                                                       
                    
        381  bytes received via SQL*Net from client                                                 
                    
          2  SQL*Net roundtrips to/from client                                                      
                    
          0  sorts (memory)                                                                         
                    
          0  sorts (disk)                                                                           
                    
          1  rows processed                                                                         
                   



Write a Review
 


All information and materials provided here are provided "as-is"; Oracle disclaims all express and implied warranties, including, the implied warranties of merchantability or fitness for a particular use. Oracle shall not be liable for any damages, including, direct, indirect, incidental, special or consequential damages for loss of profits, revenue, data or data use, incurred by you or any third party in connection with the use of this information or these materials.

About Oracle | Legal Notices and Terms of Use | Privacy Statement