SQL Server: объединение предложений WHERE. В поисках подходящей картины - PullRequest
1 голос
/ 09 октября 2009

Я хочу взять плохо спроектированный оператор SQL, который встроен в код C #, и переписать его как хранимую процедуру (предположительно), и ищу подходящие средства для решения следующего шаблона:

sql = "SELECT <whatever> FROM <table> WHERE 1=1";

if ( someCodition.HasValue )
{
    sql += " AND <some-field> = " + someCondition.Value;
}

Это упрощение. Фактический оператор довольно длинный и содержит несколько таких условий, некоторые из которых включают INNER JOIN в другие таблицы, если условие присутствует. Эта последняя часть является ключевой, иначе я бы , вероятно, смог бы решить их все с помощью:

WHERE <some-condition-value> IS NULL OR <some-field> = <some-condition-value>

Я могу придумать несколько возможных подходов. Я ищу правильный подход.

Edit: Я не хочу выполнять конкатенацию в C #. Я считаю это серьезным компромиссом для безопасности.

Ответы [ 3 ]

1 голос
/ 09 октября 2009

начать с этого предложения WHERE:

WHERE 1=1

затем добавьте все условия как:

AND <some-field> = " + someCondition.Value;

оптимизатор выбрасывает условие 1 = 1, и вам не нужно беспокоиться о слишком большом числе AND

РЕДАКТИРОВАТЬ на основании комментария ОП о нежелании объединять строки:

Вот очень полная статья о том, как обращаться с этой темой:

Условия динамического поиска в T-SQL Эрланда Соммарского

охватывает все проблемы и методы попытки написания запросов с несколькими необязательными условиями поиска.

вот оглавление:

  Introduction
      The Case Study: Searching Orders
      The Northgale Database
   Dynamic SQL
      Introduction
      Using sp_executesql
      Using the CLR
      Using EXEC()
      When Caching Is Not Really What You Want
   Static SQL
      Introduction
      x = @x OR @x IS NULL
      Using IF statements
      Umachandar's Bag of Tricks
      Using Temp Tables
      x = @x AND @x IS NOT NULL
      Handling Complex Conditions
   Hybrid Solutions – Using both Static and Dynamic SQL
      Using Views
      Using Inline Table Functions
   Conclusion
   Feedback and Acknowledgements
   Revision History
1 голос
/ 09 октября 2009

Если я правильно понимаю вопрос, идея состоит в том, чтобы заменить целый раздел кода на C #, отвечающий за создание "длинной руки", конкретного оператора SQL, соответствующего списку критериев поиска, одним вызовом хранимая процедура, которая на стороне SQL будет использовать общий шаблон запроса, предназначенный для единообразной обработки всех разрешенных комбинаций критериев поиска.

В дополнение к сложности сопоставления выражений, вычисляемых на стороне приложения (например, someCondition.HasValue), с выражениями, вычисляемыми на стороне SQL (например, "some-condition-value"), решение, которое вы представляете, может быть 1003 * логически / функционально эквивалентен «самодельному» оператору SQL, но медленнее и требовательнее к ресурсам SQL .

По сути, код C # инкапсулирует специфические знания о "физической" структуре базы данных и ее схеме . Он использует эту информацию, чтобы выяснить, когда может потребоваться конкретное СОЕДИНЕНИЕ или когда конкретное значение критерия поиска на уровне приложения переводится в SQL как «LIKE», а не как «=» предикат. Он также может включать в себя бизнес-правила, такие как «когда указан почтовый индекс, поиск выполняется по штату, а не по штату».

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

1 голос
/ 09 октября 2009

Ну, вы можете начать с

StringBuilder sb = new StringBuilder();
sb.Append("SELECT <whatever> FROM <table> WHERE  1 = 1 ");

if ( someCodition.HasValue )
{
    sb.Append(" AND <some-field> = " + someCondition.Value);
}

// And so on

Избавит вас от необходимости ставить первое ГДЕ - И

[Изменить]

Вы также можете попробовать это

Создайте SP со всеми необходимыми параметрами для таблицы и напишите запрос следующим образом.

DECLARE @sqlStatement NVARCHAR(MAX)

 @sqlStatement = " SELECT fields1, fields2 FROM TableA WHERE  1 = 1 "
if(@param1 IS NOT NULL)  @sqlStatement = @sqlStatement + "AND Column1 = " + @param1
if(@param2 IS NOT NULL)  @sqlStatement = @sqlStatement + "AND Column2 = " + @param2
// and so on 

sp_executeSql @sqlStatement

Также вы можете попробовать подобный SP, но с:

SELECT fields1, fields2 FROM TableA WHERE  1 = 1 
AND ( ( @param1 IS NULL ) OR ( Column1 = @param1 ) )
AND ( ( @param2 IS NULL ) OR ( Column2 = @param2 ) )

это определенно доказательство инъекции!

...