2011-02-17 23 views
8

Quiero buscar registros donde un campo particular COMIENCE CON alguna cadena (digamos "ar") O ese campo CONTIENE la cadena, "ar".Condiciones ponderadas en la cláusula WHERE de una instrucción SQL

Sin embargo, considero que las dos condiciones son diferentes, porque estoy limitando el número de resultados devueltos a 10 y quiero que la condición de ARRANQUES CON mayor peso que la condición CONTIENE.

Ejemplo:

SELECT * 
FROM Employees 
WHERE Name LIKE 'ar%' OR Name LIKE '%ar%' 
LIMIT 10 

El problema es que es que si hay nombres que comienzan con "ar" deben ser favorecidos. La única forma en que debería recuperar un nombre que simplemente CONTIENE "ar" es si hay MENOS de 10 nombres que INICIAN con "ar"

¿Cómo puedo hacer esto contra una base de datos MySQL?

Respuesta

10

Debe seleccionarlos en 2 partes y agregar una etiqueta de Preferencia a los resultados. 10 de cada segmento, y luego fusionar ellos y tomar de nuevo el mejor 10. Si el segmento 1 produce 8 entradas, entonces el segmento 2 de UNION Todo el producto será el 2

SELECT * 
FROM 
(
SELECT *, 1 as Preferred 
FROM Employees 
WHERE Name LIKE 'ar%' 
LIMIT 10 
UNION ALL 
SELECT * 
FROM 
(
    SELECT *, 2 
    FROM Employees 
    WHERE Name NOT LIKE 'ar%' AND Name LIKE '%ar%' 
    LIMIT 10 
) X 
) Y 
ORDER BY Preferred 
LIMIT 10 
+0

+1. De acuerdo, esto es más eficiente. – mellamokb

+0

Esto parece funcionar para mí. ¿Puedes explicarlo en absoluto?Entiendo (en términos generales) lo que significa unión. ¿Cuáles son las X e Y y qué es el 1 y el 2? –

+1

@Stephen - X e Y son solo alias dados a las subconsultas (cada tabla derivada debe tener un alias, de modo que se puedan referenciar si es necesario). Puede agregar una columna a cualquier conjunto de resultados, simplemente dando un valor y nombrando (aliasing) la columna. En este caso, agregué una columna llamada "Preferido" con un valor de 1 en la primera parte y un valor de 2 en la segunda parte. Las columnas ahora son parte del resultado (para la consulta saliente). – RichardTheKiwi

4

Asignar un valor de código de resultados, y ordenar por el valor del código:

select 
    *, 
    (case when name like 'ar%' then 1 else 2 end) as priority 
from 
    employees 
where 
    name like 'ar%' or name like '%ar%' 
order by 
    priority 
limit 10 

Editar:

Ver Richard también conocido como la respuesta de cyberkiwi una solución más eficiente si hay potencialmente una gran cantidad de partidos .

+0

Si la tabla contiene muchas coincidencias , entonces esto puede ser más lento ya que primero debe asignar una prioridad a todas las coincidencias. – RichardTheKiwi

0

Prueba esto (no tiene una instancia de MySQL inmediatamente disponible para probar con):

SELECT * FROM 
    (SELECT * FROM Employees WHERE Name LIKE 'ar%' 
    UNION 
    SELECT * FROM Employees WHERE Name LIKE '%ar%' 
    ) 
LIMIT 10 

probablemente hay mejores maneras de hacerlo, pero que inmediatamente vino a la mente.

0

Mi solución restante es:

SELECT * 
FROM Employees 
WHERE Name LIKE '%ar%' 
ORDER BY instr(name, 'ar'), name 
LIMIT 10 

instr() busca la primera aparición del patrón en cuestión. AR% vendrá antes de xxAR.

Esto evita:

  1. sólo debe hacer exploración de la tabla 1 hora. Las uniones y las tablas derivadas hacen 3. Las dos primeras en las columnas para filtrar los patrones y luego la tercera en el subconjunto para encontrar dónde son iguales, ya que la unión filtra los engaños.

  2. Da un orden verdadero basado en la ubicación del patrón. Wx> XW> XXW> etc ...

0
SELECT * 
FROM Employees 
WHERE Name LIKE 'ar%' OR Name LIKE '%ar%' 
ORDER BY LIKE 'ar%' DESC 
LIMIT 10 

caso de las órdenes de trabajo por el binario verdadero/falso para como y si index'ed deberían beneficiarse del índice

Cuestiones relacionadas