Переменная TSQL со списком значений для предложения IN - PullRequest
9 голосов
/ 21 марта 2011

Я хочу использовать предложение вдоль строк "CASE WHEN ... THEN 1 ELSE 0 END" в операторе выбора. Сложность в том, что мне нужно, чтобы он работал со значением IN @List.

Если я жестко закодирую список, он работает нормально - и работает хорошо:

SELECT
       CASE WHEN t.column_a IN ( 'value a', 'value b' ) THEN 1 ELSE 0 END AS priority
      , t.column_b
      , t.column_c
  FROM
       table AS t
 ORDER BY
       priority DESC

Я хотел бы сделать следующее:

-- @AvailableValues would be a list (array) of strings.
DECLARE
        @AvailableValues ???

 SELECT
        @AvailableValues = ???
   FROM
        lookup_table

 SELECT
        CASE WHEN t.column_a IN @AvailableValues THEN 1 ELSE 0 END AS priority
      , t.column_b
      , t.column_c
   FROM
        table AS t
  ORDER BY
        priority DESC

К сожалению, похоже, что SQL Server этого не делает - вы не можете использовать переменную с предложением IN. Так что это оставляет меня с некоторыми другими вариантами:

  1. Сделайте '@AvailableValues' строкой, разделенной запятыми, и используйте оператор LIKE. Это плохо работает.
  2. Используйте встроенную инструкцию SELECT против lookup_table вместо переменной. Опять же, не очень хорошо работает (я думаю), потому что нужно искать таблицу в каждой строке.
  3. Напишите функцию, обертывающую оператор SELECT вместо переменной. Я еще не пробовал (попробую сейчас), но, похоже, у него будет та же проблема, что и у прямого оператора SELECT.
  4. ???

Есть ли другие варианты? Производительность очень важна для запроса - она ​​должна быть очень быстрой, поскольку она подает страницу результатов поиска в реальном времени (то есть без кэширования) для веб-сайта.

Есть ли здесь другие варианты? Есть ли способ улучшить производительность одного из приведенных выше вариантов, чтобы получить хорошую производительность?

Заранее спасибо за любую помощь!

ОБНОВЛЕНИЕ: я должен был упомянуть, что 'lookup_table' в приведенном выше примере уже является табличной переменной. Я также обновил примеры запросов, чтобы лучше продемонстрировать, как я использую предложение.

ОБНОВЛЕНИЕ II: Мне пришло в голову, что предложение IN работает вне поля NVARCHAR / NCHAR (из-за исторических причин создания таблицы). Если бы я должен был внести изменения, относящиеся к целочисленным полям (т.е. через ограничения отношений PK / FK), это могло бы сильно повлиять на производительность?

Ответы [ 4 ]

7 голосов
/ 21 марта 2011

Вы можете использовать переменную в предложении IN, но не так, как вы пытаетесь это сделать.Например, вы можете сделать это:

declare @i int
declare @j int

select @i = 10, @j = 20

select * from YourTable where SomeColumn IN (@i, @j)

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

Чтобы ответить на ваш вопрос, используйте встроенный выбор.Пока вы не ссылаетесь на внешнее значение в запросе (которое может изменить результаты для каждой строки), механизм не будет повторно выбирать одни и те же данные из таблицы.

2 голосов
/ 23 марта 2011

Исходя из вашего обновления и предполагая, что таблица соответствия мала, я предлагаю попробовать что-то вроде следующего:

DECLARE @MyLookup table
 (SomeValue nvarchar(100) not null)

SELECT
   case when ml.SomeValue is not null then 1 else 0 end AS Priority   
  ,t.column_b
  ,t.column_c
 from MyTable t
  left outer join @MyLookup ml
   on ml.SomeValue = t.column_a
 order by case when ml.SomeValue is not null then 1 else 0 end desc

(Вы не можете ссылаться на псевдоним столбца «Приоритет» в предложении ORDER BY. В качестве альтернативы вы можете использовать порядковый номер так:

 order by 1 desc

но это обычно не рекомендуется.)

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

Что касается n [Var] char против int, то да, целые числа будут быстрее, хотя бы потому, что у ЦП меньше байт для перемещения ... что может быть проблемой только при обработке lot строк, так что стоит попробовать.

1 голос
/ 12 января 2016

Я решил эту проблему с помощью функции CHARINDEX.Я хотел передать строку в качестве одного параметра.Я создал строку с начальными и конечными запятыми для каждого значения, которое я хотел проверить.Затем я соединил начальные и конечные запятые со строкой, которую я хотел увидеть, находится ли параметр «in».В конце я проверил CHARINDEX> 0

DECLARE @CTSPST_Profit_Centers VARCHAR (256) 
SELECT @CTSPST_Profit_Centers = ',CS5000U37Y,CS5000U48B,CS5000V68A,CS5000V69A,CS500IV69A,CS5000V70S,CS5000V79B,CS500IV79B,'

SELECT 
   CASE
       WHEN CHARINDEX(','+ISMAT.PROFIT_CENTER+',' ,@CTSPST_Profit_Centers) > 0 THEN 'CTSPST'  
       ELSE ISMAT.DESIGN_ID  + ' 1 CPG' 
      END AS DESIGN_ID

Вы также можете сделать это в предложении where

WHERE CHARINDEX(','+ISMAT.PROFIT_CENTER+',',@CTSPST_Profit_Centers) > 0

Если вы пытаетесь сравнить числа, вам нужно преобразоватьномер текстовой строки для работы функции CHARINDEX.

1 голос
/ 21 марта 2011

Это может быть в соответствии с тем, что вам нужно.
Обратите внимание, что это предполагает, что у вас есть разрешения и входные данные очищены.

С Запуск динамических хранимых процедур

CREATE PROCEDURE MyProc (@WHEREClause varchar(255))
AS

    -- Create a variable @SQLStatement
    DECLARE @SQLStatement varchar(255)

    -- Enter the dynamic SQL statement into the
    -- variable @SQLStatement
    SELECT @SQLStatement = "SELECT * FROM TableName WHERE " + @WHEREClause

    -- Execute the SQL statement
    EXEC(@SQLStatement)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...