Pregunta

No hago un montón de SQL, y la mayoría de las veces, yo estoy haciendo operaciones CRUD. De vez en cuando voy a conseguir algo un poco más complicado. Por lo tanto, esta pregunta puede ser una pregunta novato, pero estoy listo. He estado tratando de resolver esto durante horas, y ha sido inútil.

Así, Imagine la siguiente estructura de tablas:

> | ID | Col1 | Col2 | Col3 | .. | Col8 |

Quiero seleccionar ID y una columna calculada. La columna calculada tiene un rango de 0 - 8 y que contiene el número de coincidencias con la consulta. También quiero para restringir el conjunto de resultados para incluir sólo las filas que tienen un cierto número de partidos.

Por lo tanto, de estos datos de ejemplo:

> | 1 | 'a' | 'b' | 1 | 2 |  
> | 2 | 'b' | 'c' | 1 | 2 |  
> | 3 | 'b' | 'c' | 4 | 5 |  
> | 4 | 'x' | 'x' | 9 | 9 |  

Quiero consultar el Col1 = 'A' o Col2 = 'C' o Col3 = 1 O Col4 = 5, donde el resultado calculado> 1 y tienen la mirada establecido resultado como:

> | ID | Cal |
> | 1  |  2  |
> | 2  |  2  |
> | 3  |  2  |

Estoy usando T-SQL y SQL Server 2005, si es importante, y no puedo cambiar el esquema de base de datos.

También prefiero mantenerlo como una consulta autónomo y no tiene que crear un procedimiento almacenado o tabla temporal.

¿Fue útil?

Solución

Esta respuesta va a trabajar con SQL 2005, utilizando un CTE para limpiar la tabla derivada un poco.

WITH Matches AS
(
    SELECT ID, CASE WHEN Col1 = 'a' THEN 1 ELSE 0 END + 
                CASE WHEN Col2 = 'c' THEN 1 ELSE 0 END +
                CASE WHEN Col3 = 1  THEN 1 ELSE 0 END +
                CASE WHEN Col4 = 5  THEN 1 ELSE 0 END AS Result
    FROM Table1
    WHERE Col1 = 'a' OR Col2 = 'c' OR Col3 = 1 OR Col4 = 5 
)
SELECT ID, Result
FROM Matches
WHERE Result > 1 

Otros consejos

He aquí una solución que aprovecha el hecho de que una comparación booleana devuelve los números enteros 1 ó 0:

SELECT * FROM (
  SELECT ID, (Col1='a') + (Col2='c') + (Col3=1) + (Col4=5) AS calculated
  FROM MyTable
) q
WHERE calculated > 1; 

Tenga en cuenta que usted tiene que un paréntesis porque las comparaciones booleanas + tiene mayor precedencia que =. Además, usted tiene que poner todo en una sub consulta, ya que normalmente no se puede utilizar un alias de columna en una cláusula WHERE de la misma consulta.

Puede parecer también se debe utilizar una cláusula WHERE en la subconsulta para restringir sus filas, pero con toda probabilidad, usted va a terminar con una mesa de exploración completa de todos modos por lo que probablemente no es una gran victoria. Por otro lado, si se espera que tal restricción sería en gran medida reducir el número de filas en el resultado subconsulta, a continuación, que sería la pena.


El comentario de Re Quassnoi, si no se puede tratar a las expresiones booleanas como valores enteros, debe haber una manera de hacer corresponder las condiciones booleanas a números enteros, incluso si es un poco detallado. Por ejemplo:

SELECT * FROM (
  SELECT ID, 
      CASE WHEN Col1='a' THEN 1 ELSE 0 END
    + CASE WHEN Col2='c' THEN 1 ELSE 0 END 
    + CASE WHEN Col3=1   THEN 1 ELSE 0 END
    + CASE WHEN Col4=5   THEN 1 ELSE 0 END AS calculated
  FROM MyTable
) q
WHERE calculated > 1;

Esta consulta es más amigable índice:

SELECT  id, SUM(match)
FROM    (
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col1 = 'a'
        UNION ALL
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col2 = 'c'
        UNION ALL
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col3 = 1
        UNION ALL
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col4 = 5
        ) q
GROUP BY
        id
HAVING  SUM(match) > 1

Esto sólo será eficaz si todos las columnas estás buscando son, en primer lugar, un índice y, en segundo lugar, tener una alta cardinalidad (muchos valores diferentes).

Lee este artículo en mi blog para los detalles de rendimiento:

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top