Ответ 1
Если вы находитесь на SQL Server 2008 или новее, вы можете использовать VARCHAR (MAX)
DECLARE @sql VARCHAR(MAX)
Я могу использовать следующий код для крошечных маленьких запросов:
DECLARE @sql VARCHAR(8000)
SET @sql = 'SELECT * FROM myTable'
Exec @sql
Вышеприведенный метод очень полезен для поддержки больших объемов кода, особенно когда нам нужно внести изменения один раз и отразить их повсюду.
Моя проблема заключается в том, что мой запрос (это всего лишь один запрос), который я хочу передать в переменную @sql, использует более 25 табличных объединений, некоторые из них по временным табличным переменным, включают в себя сложные операции и, следовательно, его длина превышает 8000 символов.,
Я хотел использовать тип данных TEXT для хранения этого запроса, но MSDN показывает предупреждающее сообщение о том, что Microsoft планирует удалить типы данных Text, NText и Image из своих следующих версий. Я хочу, чтобы мой код работал в будущем.
Я думал о сохранении этого запроса в отдельном файле, но, поскольку он использует объединения переменных таблицы и других параметров, специфичных для процедуры, я сомневаюсь, что это возможно.
Пожалуйста, скажите мне метод, чтобы сохранить большой запрос в переменной и выполнить его несколько раз в процедуре.
Если вы находитесь на SQL Server 2008 или новее, вы можете использовать VARCHAR (MAX)
DECLARE @sql VARCHAR(MAX)
Если у вас есть значения 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) при назначении его переменной, но к тому времени уже слишком поздно.
DECLARE @sql VARCHAR(max)
SET @sql = 'SELECT * FROM myTable'
Exec @sql
Примечание:
Print(@sql)
отображаются только первые 8000 символов!
Проблема заключается в том, что по умолчанию ваша строка имеет ограничение по 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
использовать
EXEC
(
'
--your sql script here
'
)
Вы должны прочитать ответ на этот пост, который очень хорошо объясняет ситуацию: Ограничения SQL NVARCHAR и VARCHAR
nvarchar(x)
varchar(y)
nvarchar(max)
, которая может хранить до 2 ГБ.Проблема в том, что nvarchar(max) + varchar(y) = nvarchar(max) + nvarchar(4000)
; SQL преобразует ваш varchar(y)
в nvarchar(y)
или nvarchar(4000)
, если y больше 4000 и меньше 8000, усекая вашу строку!
Хорошо, что я использовал это раньше (в SQL 2005), и могу сказать, что у вас есть два варианта:
1 - Используйте хранимую процедуру sys.sp_sqlexec, которая может принимать параметр текста типа (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 или новее глупо это делать.
Нет решения для этого, как вы это делаете. 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
Таким образом, каждый набор @Statement может иметь varchar (max), если каждый чанк находится в пределах предела размера (я вырезал реальный код в моем примере, из соображений экономии места)
Я была такая же проблема. У меня есть 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)
Перед печатью преобразуйте в группу и измените тип данных.
PRINT CAST(@sql AS NTEXT)
Теперь попробуй это.
Если вы пытаетесь сделать это в Management Studio, может помочь следующий сценарий.
DECLARE @Len INT = 5
DECLARE @Str VARCHAR(MAX) = '1111122222333334444455555'
DECLARE @TmpStr VARCHAR(MAX)
DECLARE @Return TABLE (RetStr VARCHAR(MAX))
WHILE(LEN(@Str) > 0)
BEGIN
SET @TmpStr = LEFT(@Str, @Len)
IF(LEN(@Str) > @Len)
SET @Str = RIGHT(@Str, LEN(@Str) - @Len)
ELSE
SET @Str = ''
INSERT INTO @Return SELECT @Str
END
SELECT * FROM @Return
Там @Len
должно быть 8000, поскольку это максимальная длина, которую показывает Management Studio. @Str
- это текст длиной более 8000 символов.