Ошибка преобразования при преобразовании значения nvarchar '01HP011' в тип данных int

Я получаю ошибку преобразования на одном сервере, но не на другом сервере, оба имеют одинаковую базу данных, одна тестовая, а другая живая, тест на самом деле является копией живого, но немного старым. На живом сервере включена функция AlwaysOn. когда я запустил Print @@version на обоих серверах, я получаю следующее

Microsoft SQL Server 2016 (SP1-CU1) (KB3208177) - 13.0.4411.0 (X64) 
    Jan  6 2017 14:24:37 
    Copyright (c) Microsoft Corporation
    Standard Edition (64-bit) on Windows Server 2016 Standard 6.3 <X64> (Build 14393: ) (Hypervisor)

Это SQL-запрос, который я запускаю


exec sp_executesql N'select * From DataTable
WHERE DT1 = @P1 AND DT2 = @P2
order by
cp1',N'@P1 smallint,@P2 smallint',0,0

столбец DT2 имеет смешанное значение 1, 1BAC и NULL, но я не понимаю, почему он работает на одном сервере, а не на другом.


person Declan Junior    schedule 28.09.2020    source источник
comment
Ваши типы действительно должны совпадать по разным причинам. Если DT2 не является smallint, почему вы используете smallint в предложении WHERE? Это просто сломано.   -  person pmbAustin    schedule 28.09.2020
comment
Спасибо, код написан в приложении, и оно отправляет такой запрос, но он не работает в реальном времени, но работает в тесте, и единственная разница в том, что тест немного старше, чем Live, и находится на другом сервере, 90% данных в этой таблице соответствует, так почему это работает на тесте?   -  person Declan Junior    schedule 28.09.2020
comment
Чтобы сделать очевидное утверждение, но ошибка информирует о проблеме, '01HP011' не является допустимым значением int. В int нет букв.   -  person Larnu    schedule 28.09.2020
comment
Спасибо, Ларун, я вроде догадался, о чем говорит ошибка, но мой вопрос остается прежним, почему это работает на одном, но не на другом...   -  person Declan Junior    schedule 28.09.2020
comment
Почему в одном работает, а в другом нет. Во-первых, мы должны предположить, что то, что вы утверждаете, верно — базы данных идентичны по структуре. Мы знаем, что они не имеют одинакового содержания, что является фактором. Но даже если предположить, что они это сделали, УДАЧА — вот почему это работает на одном, а не на другом. Ваш код основан на небезопасном неявном преобразовании. В счастливом случае план выполнения избегает строк, которые не могут быть преобразованы. Почему это происходит? Сравните планы и сравните доступ к строкам.   -  person SMor    schedule 29.09.2020
comment
И даже если ты знаешь почему, что тогда? Код вашего приложения должен быть исправлен — избегание ошибки не является выигрышной стратегией.   -  person SMor    schedule 29.09.2020
comment
В соответствии с правилами для приоритет типа данных при объединении SmallInt и строкового типа данных в выражении, например DT2 = @P2, строка будет преобразована в SmallInt. Вы можете использовать Cast для принудительного преобразования другим способом, например. DT2 = Cast( @P2 as VarChar(10) ).   -  person HABO    schedule 29.09.2020
comment
Спасибо, ребята, когда я узнаю, что он работает с базой данных, которая имеет ту же структуру, но меньше данных, я подумал, что это может быть какая-то настройка уровня базы данных/сервера, которая может вызывать эту проблему, поэтому я обращаюсь к вам, ребята... Еще раз спасибо   -  person Declan Junior    schedule 29.09.2020
comment
Совет. Вы можете использовать Try_Convert для выявления неправильных значений.   -  person HABO    schedule 29.09.2020


Ответы (1)


Похоже, что dt2 определяется как строка, а не как число. Вы должны выровнять тип данных вашего параметра с правильным типом данных, иначе SQL Server попытается привести строку к числу, что не удастся при таком значении, как '1ABC':

Учитывать:

exec sp_executesql 
    N'select * From DataTable WHERE DT1 = @P1 AND DT2 = @P2 order by cp1',
    N'@P1 smallint, @P2 nvarchar(10)', 0, '0'

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


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

Вот демонстрация, демонстрирующая это.

Пример данных:

dt1 | dt2  |  cp1
--: | :--- | ---:
  0 | 1    | null
  0 | 1ABC | null
  0 | null | null

Это не удается с ошибкой преобразования:

exec sp_executesql 
    N'select * From DataTable WHERE DT1 = @P1 AND DT2 = @P2 order by cp1',
    N'@P1 int, @P2 int', 0, 10

Это работает (и возвращает пустой набор результатов):

exec sp_executesql 
    N'select * From DataTable WHERE DT1 = @P1 AND DT2 = @P2 order by cp1',
    N'@P1 int, @P2 int', 1, 10
person GMB    schedule 28.09.2020
comment
Тесту уже месяц, и он также получил смешанные данные (число, строка), есть ли настройка уровня базы данных/сервера, которая может заставлять сервер sql вести себя по-другому? Также следует добавить, что условие Where одинаково на обоих серверах. не уверен, почему код приложения написан так, но все, что я пытаюсь найти, почему это работает. также Если условие всегда одинаково с одним и тем же значением, 0 , 0 и первые 1000 строк в этой таблице одинаковы. так как написан код, он всегда возвращает 0 строк - person Declan Junior; 28.09.2020