2010-06-03 9 views
5

Tengo 2 tablas, que se parecen:cómo seleccionar la información DISTINCT con TOP 1 Info y una orden desde la parte superior 1 Información

CustomerInfo(CustomterID, CustomerName) 
CustomerReviews(ReviewID, CustomerID, Review, Score) 

Quiero buscar comentarios de un hilo y volver CustomerInfo.CustomerID y CustomerInfo.CustomerName . Sin embargo, solo quiero mostrar distintos CustomerID y CustomerName junto con solo uno de sus CustomerReviews.Reviews y CustomerReviews.Score. También quiero ordenar por el CustomerReviews.Score.

No puedo encontrar la manera de hacerlo, ya que un cliente puede dejar varias revisiones, pero solo quiero una lista de clientes con su puntuación más alta.

¿Alguna idea?

+0

¿Desea buscar Revisiones para una cadena pero recuperar la puntuación más alta del cliente Revisar incluso si eso no coincide con la cadena? –

+0

¿Existe la posibilidad de que un cliente tenga más de una revisión con el mismo valor de puntaje? Y si es así, ¿los quieres a todos, o solo a uno de ellos? Y si solo uno de ellos, ¿cuál? ("No me importa" no es una opción válida.) –

+0

Solo uno de ellos, pero me gustaría que esa revisión coincidiera con la cadena. –

Respuesta

5

Ésta es la mayor-n-por-grupo de problema que ha surgido docenas de veces en desbordamiento de pila.

he aquí una solución que funciona con una función de ventana:

WITH CustomerCTE (
    SELECT i.*, r.*, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY Score DESC) AS RN 
    FROM CustomerInfo i 
    INNER JOIN CustomerReviews r ON i.CustomerID = r.CustomerID 
    WHERE CONTAINS(r.Review, '"search"') 
) 
SELECT * FROM CustomerCTE WHERE RN = 1 
ORDER BY Score; 

Y aquí es una solución que funciona de manera más amplia con RDBMS que no soportan las funciones de ventana:

SELECT i.*, r1.* 
FROM CustomerInfo i 
INNER JOIN CustomerReviews r1 ON i.CustomerID = r1.CustomerID 
    AND CONTAINS(r1.Review, '"search"') 
LEFT OUTER JOIN CustomerReviews r2 ON i.CustomerID = r2.CustomerID 
    AND CONTAINS(r1.Review, '"search"') 
    AND (r1.Score < r2.Score OR r1.Score = r2.Score AND r1.ReviewID < r2.ReviewID) 
WHERE r2.CustomerID IS NULL 
ORDER BY Score; 

estoy que muestra la función CONTAINS() porque debe utilizar la función de búsqueda de texto completo en SQL Server, sin utilizar LIKE con comodines.

+0

Gracias. Tengo habilitada la búsqueda de texto completo. –

+0

¡Muchas gracias! Esto tiene mucho más sentido, y parece que funciona bien en cuanto a rendimiento. Tengo el texto completo habilitado, y el "puntaje" al que me refería es en realidad el "rango" de la búsqueda de texto completo. No estaba seguro de si muchas personas están familiarizadas con el texto completo. Creo que puedo reemplazar "puntaje" por "rango" y unirme al CONTAINSTABLE. –

+0

¡Impresionante! Encantado de ayudar. –

0

creo que esto debería hacerlo

select ci.CustomterID, ci.CustomerName, cr.Review, cr.Score 
from CustomerInfo ci inner join 
(select top 1* 
from CustomerReviews 
where Review like '%search%' 
order by Score desc) cr on ci.CustomterID = cr.CustomterID 
order by cr.Score 
+0

¿Hay una consulta más rápida? Parece que sería muy lento con muchos registros ya que realizaré una búsqueda individual para cada registro de cliente. Gracias! –

+0

No lo sé de otra manera, ¿tiene que verificar el plan de ejecución de la consulta? – alejandrobog

1

He votado a favor de la respuesta de Bill Karwin, pero pensé que descartaría otra opción.

Utiliza un correlated subquery, que a menudo puede incurrir en problemas de rendimiento con grandes conjuntos de datos, por lo que debe usarse con precaución. Creo que la única ventaja es que la consulta es más fácil de entender de inmediato.

select * 
from [CustomerReviews] r 
where [ReviewID] = 
(
    select top 1 [ReviewID] 
    from [CustomerReviews] rInner 
    where rInner.CustomerID = r.CustomerID 
    order by Score desc 
) 
order by Score desc 

No agregué el filtro de búsqueda de cadenas, pero eso se puede agregar fácilmente.

+0

Sí, pero trato de evitar subconsultas correlacionadas si hay otra solución que no está correlacionada.La otra solución es * generalmente * más eficiente (aunque hay una excepción para cada regla). –

Cuestiones relacionadas