В SQL Server в автоматическом режиме усекает тип varchar в хранимые процедуры
по данным форуме, SQL Server (я использую 2005, но я понимаю, что это также относится к 2000 и 2008) молча усекает любой varchars вы указываете в качестве параметров хранимой процедуры длину varchar, даже если вставляете эту строку непосредственно с помощью INSERT на самом деле вызовет ошибку. например. Если я создам эту таблицу:
CREATE TABLE testTable(
[testStringField] [nvarchar](5) NOT NULL
)
затем, когда я выполняю следующее:
INSERT INTO testTable(testStringField) VALUES(N'string which is too long')
Я получаю ошибка:
String or binary data would be truncated.
The statement has been terminated.
большой. Целостность данных сохраняется, и вызывающий абонент об этом знает. Теперь давайте определим хранимую процедуру, чтобы вставить это:
CREATE PROCEDURE spTestTableInsert
@testStringField [nvarchar](5)
AS
INSERT INTO testTable(testStringField) VALUES(@testStringField)
GO
и выполнить ее:
EXEC spTestTableInsert @testStringField = N'string which is too long'
нет ошибок, 1 строка затронуты. Строка вставляется в таблицу, с testStringField как 'strin'. В SQL Server в автоматическом режиме усе хранимой процедуры .
теперь, это поведение может быть удобно время от времени, но я понимаю, что нет никакого способа, чтобы повернуть его выключено. Это очень раздражает, как я!--28-->хочу дело в ошибке, если я передаю слишком длинную строку в хранимую процедуру. Есть 2 способа бороться с этим.
во-первых, объявите сохраненный proc @testStringField параметр как размер 6, и проверяет ли своя длина над 5. Это кажется немного взломом и включает в себя раздражающее количество шаблонного кода.
во-вторых, просто объявите все параметры varchar хранимой процедуры varchar(max), а затем пусть элемент INSERT оператор в хранимой процедуре не выполняется.
последнее, кажется, работает нормально, поэтому мой вопрос: это хорошая идея, чтобы использовать varchar(max) всегда для строк в хранимых процедурах SQL Server, если я действительно хочу, чтобы сохраненный proc не работал, когда передается слишком длинная строка? Может быть, это даже лучшая практика? Молчаливое усечение, которое не может быть отключено, кажется мне глупым.
6 ответов:
Это просто - это.
Я никогда не замечал проблемы, хотя, потому что одна из моих проверок будет заключаться в том, чтобы мои параметры соответствовали длине столбца таблицы. В клиентском коде тоже. Лично я ожидал бы, что SQL никогда не увидит слишком длинные данные. Если бы я видел усеченные данные, было бы очевидно, что вызвало это кровотечение.
Если вы чувствуете потребность в varchar (max) остерегайтесь массивной проблемы производительности из-за тип данных приоритет. варчар (Макс) имеет более высокий приоритет, чем varchar(n) (самый длинный-самый высокий). Таким образом, в этом типе запроса вы получите сканирование, а не поиск, и каждое значение varchar(100) будет приведено к varchar(max)
UPDATE ...WHERE varchar100column = @varcharmaxvalueEdit:
есть открыть элемент Microsoft Connect по этому вопросу.
и это, вероятно, достойно включения в строгие настройки Эрланда Соммаркога (и соответствующий пункт Connect).
редактировать 2, после Мартинса комментарий:
DECLARE @sql VARCHAR(MAX), @nsql nVARCHAR(MAX); SELECT @sql = 'B', @nsql = 'B'; SELECT LEN(@sql), LEN(@nsql), DATALENGTH(@sql), DATALENGTH(@nsql) ; DECLARE @t table(c varchar(8000)); INSERT INTO @t values (replicate('A', 7500)); SELECT LEN(c) from @t; SELECT LEN(@sql + c), LEN(@nsql + c), DATALENGTH(@sql + c), DATALENGTH(@nsql + c) FROM @t;
спасибо, как всегда, StackOverflow за привлечение такого рода углубленного обсуждения. Я недавно просматривал свои хранимые процедуры, чтобы сделать их более надежными, используя стандартный подход к транзакциям и блокам try/catch. Я не согласен с Джо Стефанелли, что" мое предложение состояло бы в том, чтобы сделать сторону приложения ответственной", и полностью согласен с Джез:"наличие SQL Server проверить длину строки было бы гораздо предпочтительнее". Все дело для меня в использовании хранимых процедур что они написаны на родном для базы данных языке и должны выступать в качестве последней линии обороны. На стороне приложения разница между 255 и 256-это просто число без meangingless, но в среде базы данных поле с максимальным размером 255 просто не будет принимать 256 символов. Механизмы проверки приложений должны отражать бэкэнд-БД как можно лучше, но обслуживание сложно, поэтому я хочу, чтобы база данных давала мне хорошую обратную связь, если приложение ошибочно позволяет неподходящие данные. Вот почему я использую базу данных вместо кучи текстовых файлов с CSV или JSON или что-то еще.
Я был озадачен, почему один из моих SPs бросил ошибку 8152, а другой молча усек. Я, наконец, ветвился: SP, который бросил ошибку 8152, имел параметр, который позволял на один символ больше, чем связанный столбец таблицы. Столбец таблицы был установлен в nvarchar(255), но параметр был nvarchar (256). Итак, не будет ли моя "ошибка" адресовать озабоченность gbn: "массовая производительность вопрос"? Вместо использования max, возможно, мы могли бы последовательно установить размер столбца таблицы, скажем, 255, а параметр SP-всего на один символ больше, скажем, 256. Это решает проблему бесшумного усечения и не приводит к снижению производительности. По-видимому, есть еще один недостаток, о котором я не думал, но мне кажется, что это хороший компромисс.
обновление: Я боюсь, что эта техника не соответствует. Дальнейшее тестирование показывает, что я иногда могу вызвать ошибку 8152 а иногда данные просто обрезаются. Я был бы очень благодарен, если бы кто-то мог помочь мне найти более надежный способ справиться с этим.
обновление 2: Пожалуйста, смотрите ответ Pyitoechito на этой странице.
такое же поведение можно увидеть здесь:
declare @testStringField [nvarchar](5) set @testStringField = N'string which is too long' select @testStringFieldмое предложение состояло бы в том, чтобы сделать сторону приложения ответственной за проверку ввода перед вызовом хранимой процедуры.
обновление: я боюсь, что этот метод не является последовательным. Дальнейшее тестирование показывает, что иногда я могу вызвать ошибку 8152, а иногда данные молча усекаются. Я был бы очень благодарен, если бы кто-то мог помочь мне найти более надежный способ справиться с этим.
Это, наверное, происходит потому, что 256-й символ в строке пробел.
VARCHARs будет усекать конечные пробелы при вставке и просто генерировать предупреждение. Так что ваш хранится процедура беззвучно усекает ваши строки до 256 символов, а ваша вставка усекает конечный пробел (с предупреждением). Это приведет к ошибке, когда указанный символ не является пробелом.возможно, решением было бы сделать хранимую процедуру
VARCHARподходящая длина, чтобы поймать символ небелого пробела.VARCHAR(512)вероятно, будет достаточно безопасно.
одним из решений может быть:
- изменить все входящие параметры
varchar(max)- есть SP частная переменная правильной длины данных (просто скопируйте и вставьте все параметры и добавьте " int " в конце
- объявите переменную таблицы с именами столбцов, совпадающими с именами переменных
- вставьте в таблицу строку, где каждая переменная переходит в столбец с тем же именем
- выберите из таблицы во внутренний переменные
таким образом, ваши изменения в существующем коде будут очень минимальными, как в примере ниже.
это исходный код:
create procedure spTest ( @p1 varchar(2), @p2 varchar(3) )Это новый код:
create procedure spTest ( @p1 varchar(max), @p2 varchar(max) ) declare @p1Int varchar(2), @p2Int varchar(3) declare @test table (p1 varchar(2), p2 varchar(3) insert into @test (p1,p2) varlues (@p1, @p2) select @p1Int=p1, @p2Int=p2 from @testобратите внимание, что если длина входящих параметров будет больше предела, вместо того, чтобы молча отсекать строку, SQL Server выдаст ошибку.
вы всегда можете бросить оператор if в свои sp, которые проверяют их длину, и если они больше указанной длины, бросьте ошибку. Это довольно много времени, хотя и было бы больно обновить, если вы обновите размер данных.
Comments