w3schools switch example ejemplos sql sql-server tsql where-clause case-statement

switch - Cláusula WHERE condicional de T-SQL



select case sql ejemplos (3)

Cambié la consulta para usar EXISTS porque si hay más de una ubicación asociada con un POST, habría registros POST duplicados que requerirían una cláusula DISTINCT o GROUP BY para deshacerse de ...

El no-sargable

Esto llevará a cabo la peor de las posibles soluciones:

SELECT p.* FROM POSTS p WHERE EXISTS(SELECT NULL FROM LOCATIONS l WHERE l.LocationId = p.LocationId AND l.Condition1 = @Value1 AND l.SomeOtherCondition = @SomeOtherValue) AND (@IncludeBelow = 1 OR p.LocationTypeId = @LocationType)

La versión sargable, no dinámica.

Auto explicativo ....

BEGIN IF @IncludeBelow = 0 THEN SELECT p.* FROM POSTS p WHERE EXISTS(SELECT NULL FROM LOCATIONS l WHERE l.LocationId = p.LocationId AND l.Condition1 = @Value1 AND l.SomeOtherCondition = @SomeOtherValue) AND p.LocationTypeId = @LocationType ELSE SELECT p.* FROM POSTS p WHERE EXISTS(SELECT NULL FROM LOCATIONS l WHERE l.LocationId = p.LocationId AND l.Condition1 = @Value1 AND l.SomeOtherCondition = @SomeOtherValue) END

La versión dinámica, sargable (SQL Server 2005+):

Lo ames o lo odies, el SQL dinámico te permite escribir la consulta una vez. Solo tenga en cuenta que sp_executesql almacena en caché el plan de consulta, a diferencia de EXEC en SQL Server. Recomiendo encarecidamente leer la maldición y las bendiciones de SQL dinámico antes de considerar SQL dinámico en SQL Server ...

DECLARE @SQL VARCHAR(MAX) SET @SQL = ''SELECT p.* FROM POSTS p WHERE EXISTS(SELECT NULL FROM LOCATIONS l WHERE l.LocationId = p.LocationId AND l.Condition1 = @Value1 AND l.SomeOtherCondition = @SomeOtherValue)'' SET @SQL = @SQL + CASE WHEN @IncludeBelow = 0 THEN '' AND p.LocationTypeId = @LocationType '' ELSE '''' END BEGIN EXEC sp_executesql @SQL, N''@Value1 INT, @SomeOtherValue VARCHAR(40), @LocationType INT'', @Value1, @SomeOtherValue, @LocationType END

Encontré un par de preguntas similares aquí sobre esto, pero no pude averiguar cómo aplicar a mi escenario.

Mi función tiene un parámetro llamado @IncludeBelow . Los valores son 0 o 1 (BIT).

Tengo esta consulta:

SELECT p.* FROM Locations l INNER JOIN Posts p on l.LocationId = p.LocationId WHERE l.Condition1 = @Value1 AND l.SomeOtherCondition = @SomeOtherValue

Si @IncludeBelow es 0, necesito que la consulta sea esta:

SELECT p.* FROM Locations l INNER JOIN Posts p on l.LocationId = p.LocationId WHERE l.Condition1 = @Value1 AND l.SomeOtherCondition = @SomeOtherValue AND p.LocationType = @LocationType -- additional filter to only include level.

Si @IncludeBelow es 1, esa última línea debe ser excluida. (es decir, no aplicar filtro).

Supongo que debe ser una sentencia CASE , pero no puedo entender la sintaxis.

Esto es lo que he intentado:

SELECT p.* FROM Locations l INNER JOIN Posts p on l.LocationId = p.LocationId WHERE l.Condition1 = @Value1 AND l.SomeOtherCondition = @SomeOtherValue AND (CASE @IncludeBelow WHEN 0 THEN p.LocationTypeId = @LocationType ELSE 1 = 1)

Obviamente eso no es correcto.

¿Cuál es la sintaxis correcta?


Puede cambiar su estado de cuenta CASE a esto. El planificador de consultas ve esto de manera diferente, pero puede que no sea más eficiente que usar OR:

(p.LocationTypeId = CASE @IncludeBelow WHEN 0 THEN p.LocationTypeId ELSE @LocationType END)


Puedes escribirlo como

SELECT p.* FROM Locations l INNER JOIN Posts p ON l.LocationId = p.LocationId WHERE l.Condition1 = @Value1 AND l.SomeOtherCondition = @SomeOtherValue AND ((@IncludeBelow = 1) OR (p.LocationTypeId = @LocationType))

que es un patrón que se ve mucho, por ejemplo, para los parámetros de búsqueda opcionales. Pero el IIRC puede arruinar los planes de ejecución de consultas, por lo que puede haber una mejor manera de hacerlo.

Dado que es solo un poco, casi vale la pena decidir entre dos bloques de SQL con o sin la verificación, por ejemplo, ¿usar un IF en un procedimiento almacenado o con diferentes cadenas de comandos en el código de llamada, según el bit?