2015-09-28 3 views
0

У нас есть ситуация, когда пользователь может запрашивать любые (или все) поля поиска.Сохраненная процедура SqlServer с необязательными аргументами

Представьте себе следующую таблицу:

CREATE TABLE t_searchable(
    Column1 DateTime, 
    Column2 Varchar(50), 
    Column3 SmallInt) 

Все три колонки проиндексированы, и никто не являются Nullable.

Теперь пользователь может выполнить поиск по запросу диапазона дат (по Column1), запрос по Column2 и Column3 или любую их комбинацию.

Я думал о 2 способа сделать это:

первый подход:

Создание 7 различных хранимых процедур:

- Column1 
- Column2 
- Column3 
- Column1 and 2 
- Column1 and 3 
- Column2 and 3 
- Column1 and 2 and 3 

И есть клиент выбрать SP для вызова в зависимости от аргументы

2-й подход:

Создайте сингулярный СП с массами и массами IF ELSE утверждений внутри.

Оба подхода очень громоздки и не являются будущим доказательством, поскольку если мы добавим новый столбец в будущем, который нам нужно будет искать, его будет непросто реализовать, поскольку он будет касаться либо касания клиента И сервер (в случае решения 1) или сделать IF ELSE еще сложнее, чем для решения 2.

Мой вопрос: есть ли лучший способ сделать это? Я бы хотел в идеале избегать написания пользовательской инструкции SQL в коде, поскольку это может быть против политики компании (они предпочитают SP для пользовательских SQL-исполнений), но чем больше я думаю об этом, тем больше кажется неизбежным, но я думал, что буду спросите экспертов здесь (я не очень хороший @ SQL).

Большое спасибо,

+1

Вы можете использовать Dynamic-SQL, как [здесь] (http://stackoverflow.com/a/32161674/5070879) (опустить часть со временной таблицей) – lad2025

ответ

3

Вы можете сделать это, имея параметры хранимой процедуры быть необязательным, обеспечивая нулевой по умолчанию, и проверка нуль-ность параметра как часть выбора.

CREATE PROCEDURE MySearch 
    @Column1 DATETIME = NULL, 
    @Column2 VARCHAR(50) = NULL, 
    @Column3 SMALLINT = NULL 
AS 
SELECT column1,column2,column3 
FROM t_searchable 
WHERE (@Column1 IS NULL OR Column1 = @Column1) 
AND (@Column2 IS NULL OR Column2 = @Column2) 
AND (@Column3 IS NULL OR Column3 = @Column3) 
+0

Большое спасибо. Проверка этого теперь и будет обновляться, как только я узнаю, что это решение лучше, чем динамический SQL для моей usecase (производительность мудрая). – kha

+0

Нединамическое решение почти всегда будет работать лучше, чем строить sql динамически – Jamiec

2

Что вы запрашиваете, это catch-all-query.

CREATE PROCEDURE YourProcedureName 
    @column1 DATETIME NULL, 
    @column2 VARCHAR(50) NULL, 
    @column3 SMALLINT NULL 
AS 

SELECT 
    * 
FROM t_searchable 
WHERE 
    (@column1 IS NULL OR Column1 = @column1) 
    AND (@column2 IS NULL OR Column2 = @column2) 
    AND (@column3 IS NULL OR Column3 = @column3) 

Другой способ заключается в использовании динамического SQL и выполнить его с помощью sp_executesql:

CREATE PROCEDURE YourProcedureName 
    @column1 DATETIME NULL, 
    @column2 VARCHAR(50) NULL, 
    @column3 SMALLINT NULL 
AS 

DECLARE @sql NVARCHAR(MAX) 

SET @sql = 
'SELECT * 
FROM t_searchable 
WHERE 
    1 = 1' + CHAR(10) 
IF @column1 IS NOT NULL 
    SET @sql += ' AND Column1 = @column1' + CHAR(10) 

IF @column2 IS NOT NULL 
    SET @sql += ' AND Column2 = @column2' + CHAR(10) 

IF @column3 IS NOT NULL 
    SET @sql += ' AND Column3 = @column3' + CHAR(10) 

EXEC sp_executesql 
     @sql, 
     N'@column1 DATETIME, @column2 VARCHAR(50), @column3 SMALLINT', 
     @column1, 
     @column2, 
     @column3 
+0

ooh бить вас на 3 секунды! – Jamiec

+0

@ Ямец, ты быстро! Я добавил альтернативное решение. –

+0

Большое спасибо!Я попробую оба подхода и сделаю анализ производительности и отвечу в качестве ответа, если второй победитель. В противном случае мне придется уважать 3 секунды :). – kha

Смежные вопросы