2009-10-15 17 views
12

Come posso verificare una sottostringa in una stringa in Oracle senza utilizzare LIKE? Diciamo che voglio per selezionare tutti gli utenti da una tabella che hanno la lettera "z" nella loro cognome:Controllare una sottostringa in una stringa in Oracle senza LIKE

SELECT * FROM users WHERE last_name LIKE "%z%"; 

che avrebbe funzionato, ma io non voglio usare LIKE. C'è qualche altra funzione che potrei usare?

risposta

13

Immagino che la ragione per cui stai chiedendo sia la performance? C'è la funzione instr. Ma è probabile che funzioni più o meno lo stesso dietro le quinte.

Forse potresti esaminare full text search.

Come gli ultimi resort si guarderebbe la cache o colonne precomputed/una vista indicizzata.

+0

La mia ipotesi è che la ricerca a tutto testo non ti compri nulla. Solitamente indicizza le parole, non le sottostringhe. – Tomalak

+0

Ad essere sinceri, non ho mai provato Oracle. Spero che supporti comunque un qualche tipo di sistema jolly. So che il testo completo di SQL Server fa – wefwfwefwe

+0

Sì, è perché le prestazioni. Sto cercando qualcosa come strstr() in PHP. –

2

I database sono fortemente ottimizzati per scenari di utilizzo comuni (e LIKE è uno di quelli).

Non è possibile trovare un modo più rapido per eseguire la ricerca se si desidera mantenere il livello DB.

5

Se si fosse interessati solo a 'z', è possibile creare un indice basato su funzioni.

CREATE INDEX users_z_idx ON users (INSTR(last_name,'z')) 

Quindi la query utilizza WHERE INSTR(last_name,'z') > 0.

Con questo approccio è necessario creare un indice separato per ogni carattere che si desidera cercare. Suppongo che se questo è qualcosa che fai spesso, potrebbe valere la pena creare un indice per ogni lettera.

Inoltre, tieni presente che se i tuoi dati hanno i nomi in maiuscolo nel modo standard (ad esempio, "Zaxxon"), allora sia il tuo esempio che il mio non corrisponderebbero ai nomi che iniziano con una Z. Puoi correggere per questo includendo LOWER nell'espressione di ricerca: INSTR(LOWER(last_name),'z').

+3

Ancora più efficiente sarebbe solo indicizzare le righe con z ... CREATE INDEX users_z_idx ON users (Case quando INSTR (last_name, 'z')> 0 quindi 1 else null end)) –

+0

Buon punto, David. –

0

Tenere presente che vale la pena utilizzare solo una scansione completa della tabella per trovare questi valori se il numero di blocchi che contengono una riga che corrisponde al predicato è significativamente inferiore al numero totale di blocchi nella tabella. Questo è il motivo per cui Oracle rifiuta spesso l'uso di un indice per la scansione completa quando si utilizza LIKE '% x%' dove x è una stringa molto piccola. Ad esempio, se l'ottimizzatore crede che l'utilizzo di un indice richiederebbe ancora letture a blocco unico su (diciamo) il 20% dei blocchi di tabella, allora una scansione completa della tabella è probabilmente un'opzione migliore rispetto a una scansione dell'indice.

A volte si sa che il proprio predicato è molto più selettivo di quanto l'ottimizzatore possa stimare. In tal caso, è possibile esaminare fornendo un suggerimento di ottimizzazione per eseguire una scansione completa rapida dell'indice sulla colonna pertinente (in particolare se l'indice è un segmento molto più piccolo della tabella).

SELECT /*+ index_ffs(users (users.last_name)) */ 
     * 
FROM users 
WHERE last_name LIKE "%z%" 
3

Si può fare in questo modo con INSTR:

SELECT * FROM users WHERE INSTR(LOWER(last_name), 'z') > 0; 

INSTR restituisce zero se la sottostringa non è nella stringa.

Fuori interesse, perché non vuoi usare come?

Modifica: Mi sono preso la libertà di rendere insensibile la ricerca del caso in modo da non perdere Bob Zebidee.:-)

Problemi correlati