Как запустить оператор SQL длиной более 8000 символов из переменной? - PullRequest
20 голосов
/ 07 февраля 2012

Я могу использовать следующий код для крошечных маленьких запросов:

DECLARE @sql VARCHAR(8000)
SET @sql = 'SELECT * FROM myTable'
Exec @sql

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

Моя проблема в том, что мой запрос (это всего лишь один запрос), который я хочу передать в переменную @sql, использует более 25 объединений таблиц, некоторые из них во временных переменных таблицы, включают сложные операции иследовательно, его длина превышает 8000 символов.

Я хотел бы использовать тип данных TEXT для хранения этого запроса, но MSDN показывает предупреждающее сообщение о том, что Microsoft планирует удалить типы данных Text, NText и Image из следующих версий.,Я хотел бы, чтобы мой код работал и в будущем.

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

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

Ответы [ 12 ]

24 голосов
/ 22 июля 2013

Проблема заключается в неявном преобразовании.

Если у вас есть значения Unicode / nChar / nVarChar, которые вы объединяете, то SQL Server неявно преобразует вашу строку в VarChar (8000), и, к сожалению, он слишком глупПоймите, что это урежет вашу строку или даже даст вам предупреждение, что данные были урезаны по этому вопросу!

При объединении длинных строк (или строк, которые, по вашему мнению, могут быть длинными) всегда предварительно объединить строение строк с помощью CAST ('' как nVarChar (MAX)) вот так:

SET @Query = CAST('' as nVarChar(MAX))--Force implicit conversion to nVarChar(MAX)
           + 'SELECT...'-- some of the query gets set here
           + '...'-- more query gets added on, etc.

Какая боль и страшно думать, как работает SQL Server.: (

Я знаю, что другие обходные пути в Интернете говорят о том, чтобы разбить ваш код на несколько назначений SET / SELECT, используя несколько переменных, но это не нужно, учитывая решение, приведенное выше.

Для тех, кто достиг максимума в 4000 символов, это, вероятно, было связано с тем, что у вас был Unicode, поэтому он был неявно преобразован в nVarChar (4000).

Объяснение:
Что происходит за кулисами, так это то, что, хотяПри использовании переменной (MAX), которую вы назначаете, SQL Server оценивает правую часть значения, которое вы назначаете первым, и по умолчанию присваивает nVarChar (4000) или VarChar (8000) (в зависимости от того, что вы объединяете).После определения значения (и после его усечения) оно преобразуется в (MAX) при назначении переменной, но к тому времени уже слишком поздно.

16 голосов
/ 07 февраля 2012

Если вы используете SQL Server 2008 или новее, вы можете использовать VARCHAR (MAX)

DECLARE @sql VARCHAR(MAX)
6 голосов
/ 24 мая 2013
DECLARE @sql VARCHAR(max)
SET @sql = 'SELECT * FROM myTable'
Exec @sql

Примечание:

Print(@sql)

показывает только первые 8000 символов!

4 голосов
/ 07 февраля 2012

Проблема в том, что ваша строка по умолчанию имеет ограничение в 8000 символов.Чтобы предотвратить это, вы должны преобразовать его в (N) VARCHAR (MAX)

DECLARE @sql VARCHAR(8000)
        SET @sql = CAST('SELECT * FROM myTable' AS VARCHAR(MAX))
--Check length of variable
 PRINT 'Length is: '+CAST(LEN(@sql) AS VARCHAR)+ 'symbols'
        Exec @sql
3 голосов
/ 05 апреля 2016

Вам следует прочитать ответ на этот пост, который очень хорошо объясняет ситуацию: SQL NVARCHAR и VARCHAR Limits

  1. Если длина x вашей строки меньше 4000 символов,строка будет преобразована в nvarchar(x)
  2. Если длина y составляет от 4000 до 8000, varchar(y)
  3. Если длина превышает 8000 символов, nvarchar(max), которая может хранитьдо 2 ГБ.

Проблема в том, что nvarchar(max) + varchar(y) = nvarchar(max) + nvarchar(4000);SQL преобразует ваш varchar(y) в nvarchar(y) или nvarchar(4000), если y больше 4000 и меньше 8000, обрезая вашу строку!

3 голосов
/ 07 февраля 2012

использование

EXEC
(
  '
   --your sql script here
  '
)
2 голосов
/ 07 февраля 2012

Я уже работал с этим раньше (в SQL 2005) и могу сказать, что у вас есть два варианта:

1 - использовать хранимую процедуру sys.sp_sqlexec, которая может принимать параметр типа text (IMO).это путь)Не против предупреждения.В SQL 2008 ntext все еще поддерживается, и если вы выполните там varchar (max), он будет работать.Таким образом, в основном, если у вас 2008, текстовое решение и varchar (max) будут работать, так что у вас будет время изменить его = -).В 2012 году, однако, будет работать только varchar (max), поэтому вам придется изменить его перед обновлением.

2- (это то, что я сделал вначале) Проверьте ЭТОТ пост: http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=52274 и делать то, что говорит пользователь "Кристен".Работал как шарм для меня.Не забудьте предварительно установить для них пустую строку.Если вы поняли мой пост, вы уже знаете, что в SQL 2008 или новее это глупо.

1 голос
/ 26 февраля 2016

Нет решения для этого на пути, которым вы это делаете.MsSql с 2012 года поддерживает, например, Ntext, что позволяет вам выходить за пределы 8000 символов в переменной.Чтобы решить эту проблему, нужно создать в таблице несколько переменных или несколько строк, через которые вы можете выполнять итерацию.

В лучшем случае в версии MsSql максимальный размер переменной составляет 8000 символов в последней версии на момент, когдаэто было напечатано.Так что, если вы имеете дело со строкой, скажем, 80000 символов.Вы можете разбить данные на десять переменных по 8000 символов каждая (8000 x 10 = 80 000) или разбить переменную на части и поместить в таблицу, например, LongTable (Bigstring Varchar (8000)), вставить в нее 10 строк и использоватьЗначение идентификатора, чтобы вы могли извлекать данные в том же порядке.

Метод, который вы пытаетесь использовать, в настоящее время не работает с MsSql.

Еще одна неясная опция, которая будет работать, но не рекомендуется, это хранитьпеременная в текстовом файле с помощью команд командной оболочки для чтения / записи файла.Тогда у вас есть доступное пространство за пределами 8000 символов.Это медленно и менее безопасно, чем другие методы, описанные выше.

0 голосов
/ 03 июня 2019

Перед печатью преобразуйте в приведение и измените тип данных.

PRINT CAST(@sql AS NTEXT)

Теперь попробуйте.

0 голосов
/ 22 января 2019

У меня была такая же проблема.У меня есть SQL, который был более 21 000 символов.По какой-то причине

Declare @SQL VARCHAR(MAX)

EXEC(@SQL) 

может привести к нескольким проблемам

Мне пришлось окончательно разделить его на несколько переменных, и тогда это сработало.

    Declare @SQL1 VARCHAR(MAX) = 'First Part'
    Declare @SQL2 VARCHAR(MAX) = 'Second  Part'
    Declare @SQL3 VARCHAR(MAX) = 'Third Part'
    Declare @SQL4 VARCHAR(MAX) = 'Fourth Part'

    Set @SQL= @SQL1 + @SQL2 + @SQL3 + @SQL4

    EXEC(@SQL)
...