Buscar el underscore con Like

16/08/2008 - 16:37 por Carlos | Informe spam
Quiero hacer una busqueda con like:

select campos... from tabla where campo1 like '%_%

para encontrar los campo1's que contengan un underscore pero resulta que el
underscore es un comodin reservado que se usa para reemplazar cualquier
caracter.

Como hago para configurar esta condicion ?

Gracias
 

Leer las respuestas

#1 Alejandro Mesa
17/08/2008 - 00:56 | Informe spam
Carlos,

1 - Puedes encerrar el underscore entre corchetes, lo cual indica el
caracter a buscar y le quita el significado como comodin de busqueda.

select c1
from (select 'table_con_underscore' as c1 union all select
'tablasinunderscore') as t
where c1 like '%[_]%'

2 - Puedes usar la clausula ESCAPE para indicar que no se considere ese
caracter de la forma comun.

select c1
from (select 'table_con_underscore' as c1 union all select
'tablasinunderscore') as t
where c1 like '%\_%' escape '\'

A pesar de que ambos metodos generan el mismo resultado, el segundo metodo
tiene el incoveniente de que evita que el optimizador use las estadisticas de
cadena en un indice por una columna char / varchar / nchar / nvarchar, cuando
se usa un patron de busqueda que usa el comodin % en el inicio de la cadena,
como '%\_%'. Esta facilidad se introdujo en SQL Server 2005.

Fijate que diferente los planes de ejecucion de estas dos sentencias.

use AdventureWorks
go

sp_helpindex 'Person.Person'
go

dbcc show_statistics ('Person.Person',
'IX_Person_LastName_FirstName_MiddleName') with STAT_HEADER
go

set showplan_text on
go

select *
from Person.Person
where LastName like '%[_]%'
go

select *
from Person.Person
where LastName like '%\_%' escape '\'
go

set showplan_text off
go

Resultado:


Plan 1

|--Nested Loops(Inner Join, OUTER
REFERENCES:([AdventureWorks2008].[Person].[Person].[BusinessEntityID]))
|--Index
Scan(OBJECT:([AdventureWorks2008].[Person].[Person].[IX_Person_LastName_FirstName_MiddleName]),
WHERE:([AdventureWorks2008].[Person].[Person].[LastName] like N'%[_]%'))
|--Clustered Index
Seek(OBJECT:([AdventureWorks2008].[Person].[Person].[PK_Person_BusinessEntityID]),
SEEK:([AdventureWorks2008].[Person].[Person].[BusinessEntityID]=[AdventureWorks2008].[Person].[Person].[BusinessEntityID]) LOOKUP ORDERED FORWARD)

Plan 2

|--Clustered Index
Scan(OBJECT:([AdventureWorks2008].[Person].[Person].[PK_Person_BusinessEntityID]),
WHERE:([AdventureWorks2008].[Person].[Person].[LastName] like N'%\_%' escape
N'\' ))


Si te fijas en el resultado de el comando DBCC, notaras que la columna
"String Index" tiene valor "YES", lo cual indica que se mantienen
estadisticas sobre las diferentes valores de la columna "LastName".

Este indice no cubre todas las columnas referenciadas por la sentencia
"select", ya que usa "*", lo cual referencia todas las columnas de la tabla,
mientras que las unicas columnas que cubre el indice son [LastName],
[FirstName], y [MiddleName], por lo que SQL Server necesita ir de todas
maneras al indice clustered para traer toda la data necesaria. Ahora, se
puede escanear todo el indice clustered para encontrar las filas deseadas o
escanear el indice mencionado (el scan se debe a que se usa "%" como inicio
de el patron de busqueda), el cual es mas angosto y menos costoso de scanear,
si las filas que cumplen con la condicion son pocas (esto se sabe por las
estadisticas indicadas anteriormente) entonces se escanea el indice
nonclustered, se toma la clave de la fila en el indice clustered y se accesa
el indice clustered, usando una operacion "seek", para traer el resto de la
data.

Fijate que ese es el compartamiento para la sentencia que usa el patron
'%[_]%', no asi la sentencia que usa la clausula o palabra clave "escape".


AMB


"Carlos" wrote:

Quiero hacer una busqueda con like:

select campos... from tabla where campo1 like '%_%

para encontrar los campo1's que contengan un underscore pero resulta que el
underscore es un comodin reservado que se usa para reemplazar cualquier
caracter.

Como hago para configurar esta condicion ?

Gracias


Preguntas similares