Сложный фильтр запросов с использованием Like() в T-SQL

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

Я пишу SQL-скрипт, который мы хотим, чтобы наша бухгалтерская команда могла редактировать, не занимаясь проектированием.

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

Проблема, с которой мы сталкиваемся, заключается в том, что мы хотим, чтобы команда учета могла указать используемый фильтр. Например:

 DECLARE @year INT
DECLARE @month INT
DECLARE @filter VARCHAR(30);

SET @year = 2010
SET @month = 7
SET @filter = '%test%'
  

Здесь команда может изменить месяц и год, которые возвращают последующие запросы. В этом примере они также могут определить ОДИН элемент фильтра, исключая любые записи, в которых имя пользователя содержит строку 'test' .

Мой вопрос заключается в том, существует ли способ указать OR для LIKE() . Например, в идеале мы должны иметь @filter переменную в виде чего-то вроде '%test% , или %other% . Теперь я знаю, что это ненастоящий синтаксис, но мне интересно, есть ли синтаксис, который позволяет мне достичь этого. Я нахмурился MSDN на LIKE() синтаксис без радости. Должен ли я использовать какое-то другое выражение запроса?

Комментарии:

1. Для этого вы могли бы использовать CLR и регулярные выражения. В синтаксисе шаблона Like нет | оператора. Или вы могли бы передавать различные литералы в TVP (предполагая SQL Server 2008) и присоединяться к ним с помощью LIKE .

Ответ №1:

Вероятно, проще всего было бы просто использовать несколько параметров, хотя это и не очень красиво:

 SET @filter_1 = '%test%'
SET @filter_2 = '%foo%'
SET @filter_3 = '%'
SET @filter_4 = '%'

SELECT *
FROM BAR
WHERE var LIKE @filter_1
   OR var LIKE @filter_2
   OR var LIKE @filter_3
   OR var LIKE @filter_4
   OR var LIKE @filter_5
  

Если по умолчанию они равны%, они всегда будут совпадать по умолчанию.

Вы также могли бы использовать динамический SQL и локальную табличную переменную. По сути, создайте локальную таблицу с одним столбцом, разрешите им изменять инструкции INSERT в этой таблице, затем определите цикл, который перебирает содержимое этой таблицы для динамической генерации предложений LIKE. Это сработало бы, но потребовало бы немного больше кода. Приведенный выше пример быстрый и грязный, но я бы предположил, что этого, вероятно, достаточно для того, что вам нужно сделать.

Комментарии:

1. спасибо, я продолжаю с этим. Как вы говорите, это некрасиво, но он выполняет свою работу.

Ответ №2:

Я бы использовал соединение с LIKE предикатом. Вы можете выполнить следующий пример кода в окне запроса, чтобы увидеть, как это работает:

 DECLARE @tblFilter TABLE
    (sFilter nvarchar(MAX) NOT NULL);
INSERT @tblFilter 
    SELECT * FROM (VALUES ('%one%'), ('%two%'), ('%three%')) v(s);

DECLARE @tblData TABLE 
    (iId int NOT NULL PRIMARY KEY IDENTITY, 
     sData nvarchar(MAX));
INSERT @tblData(sData) 
    SELECT * FROM (VALUES ('one'), ('two three'), ('four')) v(s);

SELECT DISTINCT iId 
    FROM @tblData d 
    JOIN @tblFilter f ON d.sData LIKE f.sFilter;
  

Я предполагаю, что разные строки запроса находятся в @tblFilter таблице, которая может быть TVP, исходящей из значений XML, из значений, разделенных запятыми, из временной таблицы или чего-то еще.