Cinco años tarde a la fiesta.
Se menciona en los enlaces provistos de la respuesta aceptada, pero creo que merece una respuesta explícita sobre SO - construyendo dinámicamente la consulta en función de los parámetros proporcionados. Ej .:
Configuración
-- drop table Person
create table Person
(
PersonId INT NOT NULL IDENTITY(1, 1) CONSTRAINT PK_Person PRIMARY KEY,
FirstName NVARCHAR(64) NOT NULL,
LastName NVARCHAR(64) NOT NULL,
Title NVARCHAR(64) NULL
)
GO
INSERT INTO Person (FirstName, LastName, Title)
VALUES ('Dick', 'Ormsby', 'Mr'), ('Serena', 'Kroeger', 'Ms'),
('Marina', 'Losoya', 'Mrs'), ('Shakita', 'Grate', 'Ms'),
('Bethann', 'Zellner', 'Ms'), ('Dexter', 'Shaw', 'Mr'),
('Zona', 'Halligan', 'Ms'), ('Fiona', 'Cassity', 'Ms'),
('Sherron', 'Janowski', 'Ms'), ('Melinda', 'Cormier', 'Ms')
GO
Procedimiento
ALTER PROCEDURE spDoSearch
@FirstName varchar(64) = null,
@LastName varchar(64) = null,
@Title varchar(64) = null,
@TopCount INT = 100
AS
BEGIN
DECLARE @SQL NVARCHAR(4000) = '
SELECT TOP ' + CAST(@TopCount AS VARCHAR) + ' *
FROM Person
WHERE 1 = 1'
PRINT @SQL
IF (@FirstName IS NOT NULL) SET @SQL = @SQL + ' AND FirstName = @FirstName'
IF (@LastName IS NOT NULL) SET @SQL = @SQL + ' AND FirstName = @LastName'
IF (@Title IS NOT NULL) SET @SQL = @SQL + ' AND Title = @Title'
EXEC sp_executesql @SQL, N'@TopCount INT, @FirstName varchar(25), @LastName varchar(25), @Title varchar(64)',
@TopCount, @FirstName, @LastName, @Title
END
GO
Uso
exec spDoSearch @TopCount = 3
exec spDoSearch @FirstName = 'Dick'
Pros:
- fácil de escribir y entender
- flexibilidad - generar fácilmente la consulta para filtrados más difíciles (por ejemplo, TOP dinámico)
Contras:
- posibles problemas de rendimiento en función de los parámetros previstos, índices y volumen de datos
No es una respuesta directa, pero relacionado con el problema conocido como el cuadro grande
Normalmente, estos procedimientos almacenados de filtrado no flotan, pero se llaman desde alguna capa de servicio. Esto deja la opción de alejar la lógica comercial (filtrado) de SQL a la capa de servicio.
Un ejemplo es el uso LINQ2SQL para generar la consulta basada en filtros proporcionados:
public IList<SomeServiceModel> GetServiceModels(CustomFilter filters)
{
var query = DataAccess.SomeRepository.AllNoTracking;
// partial and insensitive search
if (!string.IsNullOrWhiteSpace(filters.SomeName))
query = query.Where(item => item.SomeName.IndexOf(filters.SomeName, StringComparison.OrdinalIgnoreCase) != -1);
// filter by multiple selection
if ((filters.CreatedByList?.Count ?? 0) > 0)
query = query.Where(item => filters.CreatedByList.Contains(item.CreatedById));
if (filters.EnabledOnly)
query = query.Where(item => item.IsEnabled);
var modelList = query.ToList();
var serviceModelList = MappingService.MapEx<SomeDataModel, SomeServiceModel>(modelList);
return serviceModelList;
}
Pros:
consulta
- generado dinámicamente basado en filtros proporcionados.No hay parameter sniffing o recompile consejos necesarios
- algo más fácil de escribir para aquellos en el mundo POO
- normalmente el rendimiento de usar, ya que se emitirán las preguntas "simples" (índices adecuados aún se necesitan sin embargo)
Contras:
- limitaciones LINQ2QL se pueden alcanzar y forzar una rebaja a LINQ2Objects o regresar a la solución pura de SQL según el caso
- escritura descuidada de LINQ podría generar consultas terribles (o muchas consultas, si las propiedades de navegación embarcada)
un vistazo aquí: http://stackoverflow.com/questions/11396919/building-dynamic-where-clause -in-stored-procedure/25473624 # 25473624 –
Intente seguir la instrucción where: 'code' ISNULL (FirstName, ') = ISNULL (@FirstName,' ') - esto hará que cada NULL sea una cadena vacía y aquellos se puede comparar a través de eq. operador. Si desea obtener todos los títulos si el parámetro de entrada es nulo, intente algo como eso: 'code'FirstName = @FirstName OR @FirstName IS NULL. – baHI