Использование локальной переменной для условия критерия IN с SQL Server

Возможный дубликат:
SQL: в предложение в хранимой процедуре: как передавать значения

Я использую MS SQL Server 2005 и пытаюсь написать двухэтапный сценарий:

  1. Запросить в таблице список идентификаторов, соответствующих определенным критериям
  2. Обновите поле в этой таблице, где идентификатор находится в списке идентификаторов, возвращаемых первым

Проблема в том, что шаги 1 и 2 могут быть разделены значительной временной задержкой и выполняться в разных сеансах. Существенно, что список идентификаторов, используемых в №2, представляет собой исторические данные: значения, которые №1 вернул в прошлый момент времени.

Я попытался записать все идентификаторы из # 1 в varchar (8000) в формате "##, ##, ##, ##," (эта часть отлично работает), а затем использовать эту строку как:

UPDATE table SET field=newValue WHERE (id IN (@varcharOfCommaSeparatedIDs))

Но это дает мне синтаксическую ошибку, заявляя, что он не может преобразовать это значение varchar во все, что необходимо (сообщение об ошибке усекается)

Есть ли способ сделать это, не помещая всю команду SQL в строку и не выполняя ее (используя EXEC или sp_executesql)? После многих лет избегания инъекционных атак у меня возникло инстинктивное (и, возможно, иррациональное) отвращение к «динамическому SQL».


person DaveD    schedule 14.07.2011    source источник
comment
Это выполнимо, но решения либо уродливые, либо слишком сложные. Я нашел несколько объяснений SO на прошлой неделе, когда искал это.   -  person Teddy    schedule 14.07.2011
comment
Использованный вами синтаксис недействителен, однако существуют методы, которые можно использовать при передаче данных CSV в хранимые процедуры. Имейте в виду, что большинство из них довольно уродливые, но они делают свою работу.   -  person Justin    schedule 14.07.2011
comment
@Kragen - это не обман, поскольку его требование состоит в том, чтобы список передавался между разными процессами / сеансами.   -  person JNK    schedule 14.07.2011
comment
Краген прав, этот вопрос достаточно близок, чтобы ответить на мой. Это не совсем тот же сценарий, но мне нужны результаты первого шага в формате, который можно сохранить за пределами SQL (например, в строке или наборе результатов в приложении), а затем передать обратно в # 2 (что ограничивает меня к строке / varchar) позже. Я, вероятно, должен был прямо указать это требование в вопросе, приношу свои извинения за то, что не сделал этого, и спасибо всем, кто ответил ... Теперь, как я могу отметить это как ответ / обман?   -  person DaveD    schedule 14.07.2011


Ответы (2)


Просто запишите это в таблицу.

IF EXISTS (SELECT 1 FROM Database.dbo.MyHoldingTable)
DROP TABLE Database.dbo.MyHoldingTable

SELECT <fields>
INTO Database.dbo.MyHoldingTable
FROM <other table>
WHERE <conditions>

Тогда позже:

UPDATE OtherTable
Set Column=NewValue
WHERE ID IN (SELECT id FROM Database.dbo.MyHoldingTable)

Также обратите внимание, что вы также можете использовать INNER JOIN в своей таблице вместо предложения IN, если хотите.

person JNK    schedule 14.07.2011
comment
Я не могу загромождать эту производственную среду таблицами, используемыми для таких скриптов :( - person DaveD; 14.07.2011
comment
@ Дэйв - Это не беспорядок. Поместите его в WorkTable базу данных, отбросьте, когда закончите с ним. Если ваше требование состоит в том, чтобы составить список, а затем через какое-то неопределенное время в других сеансах или ссылаться на этот список, вот как вы это делаете. - person JNK; 14.07.2011
comment
Или использовать временные таблицы или переменные таблицы? Но постарайтесь не хранить наборы записей в виде строк, если этого можно избежать. (по моему мнению) - person MatBailie; 14.07.2011
comment
Наши определения беспорядка различны;) Для конкретного проекта, над которым я работаю, список значений, возвращаемых с шага № 1, просто не может быть сохранен в БД, сценарий должен быть ненавязчивым и иметь какое-либо долгосрочное хранение. вне SQL. - person DaveD; 14.07.2011
comment
@Dave - затем сохраните список на уровне вашего приложения. Если вы используете тот же сеанс, вы можете сохранить дату в таблице #temp, если это необходимо. - person JNK; 14.07.2011

Если вы передаете значения между SP на SQL Server, я настоятельно рекомендую хранить значения в таблицах ...
- Temp Tables (#mytable)
- Table Variables (@table)
- Реальные столы

Начиная с SQL Server 2008, вы можете иметь входные параметры с табличным значением ...


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

SELECT
  *
FROM
  foo
INNER JOIN
  dbo.bar(@mystring) AS bar
    ON foo.id = bar.id
person MatBailie    schedule 14.07.2011