Как запустить более 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 символов!
проблема в том, что ваша строка по умолчанию имеет ограничение 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 пределы
- если длина X вашей строки меньше 4000 символов, строка будет преобразована в
nvarchar(x)
- если длина y между 4000 и 8000,
varchar(y)
- если длина больше, чем 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) до тех пор, пока каждый кусок сам находится в пределах предела размера (я вырезал фактический код в моем примере по соображениям экономии места)