2009-07-22 6 views
3

У меня есть таблица с несколькими полями в ней. Я пытаюсь создать фильтр поиска в asp.net, чтобы пользователь мог искать по одной или комбинации полей. Поэтому в основном я хочу, чтобы создать единый хранимую процедуру, которая принимает в 4 Params и добавит параметров в ИНЕКЕ, если его не нулевые ...SQL Filter Query

TableExample имеет 4 колонки, Col1 Col2 Col3 COL4

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

Я пытался что-то вроде этого, что неверно, но его то, что ive получил до сих пор.

СПАСИБО!

CREATE PROCEDURE [dbo].[Search] 
    @Col1 int, 
    @Col2 int, 
    @Col3 int, 
    @Col4 int 
AS 

SET TRANSACTION ISOLATION LEVEL READ COMMITTED 

SELECT * 

FROM 
    [dbo].[TestTable] 
WHERE 
    1=1 
    CASE   
     WHEN @Col1 IN NOT NULL 
     THEN AND [Col1] = @Col1 

     WHEN @Col2 IN NOT NULL 
     THEN AND [Col2] = @Col2 

     WHEN @Col3 IN NOT NULL 
     THEN AND [Col3] = @Col3 

     WHEN @Col4 IN NOT NULL 
     THEN AND [Col4] = @Col4 
    END 
+0

Так Что является консенсус, будет лучше просто построить строку запроса в стороне кода в C# затем сделать запрос, вместо того, чтобы пытаться иметь ХП сборки динамически ? Кажется, есть некоторые подводные камни с сохраненным методом proc ... – Gabe

ответ

0

Благодарю вас всех за ваши ответы. Однако, я сделал это немного по-другому. Надеюсь, это поможет кому-то! Вот как я пошел об этом:

CREATE PROCEDURE [dbo].[TestTable_Search] 
    @Col1 int, 
    @Col2 uniqueidentifier, 
    @Col3 datetime, 
    @Col4 datetime 
AS 

SET TRANSACTION ISOLATION LEVEL READ COMMITTED 

SELECT * 

FROM 
    [dbo].[TestTable] 
WHERE 
    [Col1] = COALESCE(@Col1, Col1) AND 
    [Col2] = COALESCE(@Col2, Col2) AND 
    [Col3] >= COALESCE(@Col3 + "00:00:00", Col3) AND 
    [Col4] <= COALESCE(@Col4 + "23:59:59", Col4) 
0

Вы должны были бы использовать динамический SQL, чтобы сделать это:

CREATE PROCEDURE [dbo].[Search] 
    @Col1 int, 
    @Col2 int, 
    @Col3 int, 
    @Col4 int 
AS 

DECLARE @SQL nvarchar(MAX) 

SET TRANSACTION ISOLATION LEVEL READ COMMITTED 

SET @SQL = 'SELECT * 
       FROM [dbo].[TestTable] 
      WHERE 1=1 ' 

IF @Col1 IS NOT NULL 
SET @SQL = @SQL + ' AND Col1 = ''' + @Col1 + ''' ' 

IF @Col2 IS NOT NULL 
SET @SQL = @SQL + ' AND Col2 = ''' + @Col2 + ''' ' 

IF @Col3 IS NOT NULL 
SET @SQL = @SQL + ' AND Col3 = ''' + @Col3 + ''' ' 

IF @Col4 IS NOT NULL 
SET @SQL = @SQL + ' AND Col4 = ''' + @Col4 + ''' ' 

exec sp_executesql @SQL 

END 

Имейте в виду, что есть опасность для этого, в том числе инъекции SQL, а также множество других проблем с разрешениями, которые может возникнуть, так как это динамический SQL, но это единственный способ добиться этого в слое базы данных. Если вы хотите создать запрос на уровне приложения (на C#), вы можете более эффективно защищаться от атак SQL-инъекций.

Некоторые динамические ссылки SQL, которые могут помочь вам понять недостатки:

http://www.sommarskog.se/dynamic_sql.html http://slashstar.com/blogs/tim/archive/2006/10/12/The-Prevalence-and-Dangers-of-SQL-Injection.aspx

2

Используйте тот факт, что и короткого замыкания. Я предположил, что -1 не является допустимым значением.

CREATE PROCEDURE [dbo].[Search] 
    @Col1 int = -1, 
    @Col2 int = -1, 
    @Col3 int = -1, 
    @Col4 int = -1 
AS 
Begin 
SET TRANSACTION ISOLATION LEVEL READ COMMITTED 

SELECT * 

FROM 
    [dbo].[TestTable] 
WHERE 
(@Col1 = -1 OR [Col1] = @Col1) 
and 
(@Col2 = -1 OR [Col2] = @Col2) 
and 
(@Col3 = -1 OR [Col3] = @Col3) 
and 
(@Col4 = -1 OR [Col4] = @Col4) 



END 
+1

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

+1

Отличный способ сделать это без использования динамического SQL, так как вы заранее знаете имена столбцов. Вы могли бы даже сделать это с исходными значениями NULL, просто изменив строки WHERE на «(@ Col1 IS NULL ИЛИ [Col1] = @ Col1)», который оставил бы -1 в качестве допустимого значения. – SqlRyan

+0

Не использовать null для ints - это просто моя привычка;) – cmsjr

1

Вы можете сделать это с методом, аналогичным тому, что у вас есть:

WHERE 
    CASE 
    WHEN @Col1 IS NULL THEN true 
    ELSE [Col1] = @Col1 
    END 
AND 
    CASE 
    WHEN @Col2 IS NULL THEN true 
    ELSE [Col2] = @Col2 
    END 
... 

Или вы можете сделать это намного проще, хотя, возможно, менее читаемыми:

WHERE (@Col1 IS NULL OR [Col1] = @Col1]) 
    AND (@Col2 IS NULL OR [Col2] = @Col2]) 
    AND ... 
2

поиск один из редких вариантов, которые я проповедую с использованием динамического sql или построения вашей строки sql в коде. если у вас есть всякая среда sproc, используйте динамический sql в вашем sproc. параметризировать его и использовать sp_executeSQL для его запуска, чтобы избежать SQL-инъекции