Как запустить более 8000 символов SQL-оператора из переменной?

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

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

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

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

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

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

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

спасибо заранее!

10 ответов


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

DECLARE @sql VARCHAR(MAX)

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

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

При объединении длинных строк (или строк, которые вы чувствуете, могут быть длинными) всегда pre-concatenate ваше здание строки с CAST ("as 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. : (

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

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

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


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

Примечание:

Print(@sql)

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


использовать

EXEC
(
  '
   --your sql script here
  '
)

проблема в том, что ваша строка по умолчанию имеет ограничение 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

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

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

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


вы должны прочитать ответ на этот пост, который объясняет очень хорошо : SQL nvarchar и varchar пределы

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

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


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

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

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

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


ALTER PROCEDURE [dbo].[spGetEmails]
AS
BEGIN
    SET NOCOUNT ON;
    -- Insert statements for procedure here

    declare @p varbinary(max)
set @p = 0x
declare @local table (col text)

SELECT   @p = @p + 0x3B + CONVERT(varbinary(100), Email)
 FROM tbCarsList
 where email <> ''
 group by email
 order by email

 set @p = substring(@p, 2, 10000000)

 insert @local values(cast(@p as varchar(max)))
 select   col from @local


END

У меня была такая же проблема, с усеченными строками. Я узнал, что вы можете выполнить оператор sp_executesql несколько раз.

Так как мой блок кода был намного выше предела 4k / Max, я разбиваю его на маленькие куски, как это:

set @statement = '                                                                                      
update pd                               
set pd.mismatchtype = 4                             
  FROM [E].[dbo].[' + @monthName + '_P_Data] pd                             
  WHERE pd.mismatchtype is null '                                                                               
exec sp_executesql @statement                               


set @statement = 'Select * from xxxxxxx'
exec sp_executesql @statement

set @statement = 'Select * from yyyyyyy '
exec sp_executesql @statement

end

таким образом, каждый оператор set @может иметь varchar (max) до тех пор, пока каждый кусок сам находится в пределах предела размера (я вырезал фактический код в моем примере по соображениям экономии места)