Как поле базы данных INT сравнивается с типом VARCHAR - PullRequest
2 голосов
/ 10 ноября 2010

У меня есть следующая хранимая процедура, но я не пишу полную хранимую процедуру, но некоторые из них:

@course int = null,
    SET @query = @query + 'Where course_id='+ cast(@course as varchar)

Я хочу знать, когда я конвертировал @course как тип VARCHAR, когда мой course_id в базе данных имеет тип INT - как происходит сравнение?

Ответы [ 4 ]

6 голосов
/ 10 ноября 2010

Сравнение двух разных типов в SQL Server происходит следующим образом:

  • Сначала сравнивается приоритет двух типов на основе правил Приоритет типа данных :

    тип данных с более низким приоритетом преобразуется в тип данных с более высоким приоритетом

  • следующий тип с более низким приоритетом приводитсядля типа с более высоким приоритетом

  • затем проводится сравнение между исходным значением типа с более высоким приоритетом и преобразованным значением типа с более низким приоритетом

Дляради обсуждения: INT (старшинство 16, высокий) и VARCHAR (старшинство 27, низкий) сравнили бы, приведя VARCHAR к INT, а затем сравнив их.

В вашем случае, хотя преобразования не происходит, потому что происходит то, что значение @course добавляется к динамически построенному @sql.Излишне говорить, что это плохо.правильное решение состоит в том, чтобы передать @course в качестве параметра для вызова динамического SQL:

@course INT = null
...
 SET @query = @query + 'Where course_id= @course';
...
exec sp_executesql @sql, '@course int', @course;

Это:

  • быстрее : параметризованныйзапрос вместо жесткого кодированного значения
  • безопаснее : снизить риск внедрения SQL-кода, если код подвергается рефакторингу, и @counter становится типом, который может выполнять внедрение SQL
  • менее подвержен ошибкам : нет риска распространения значения NULL для аннулирования всего @sql
4 голосов
/ 10 ноября 2010

Логическое обоснование кода, который вы опубликовали, заключается в том, что изменение типа данных должно произойти для SQL Server, чтобы разрешить конкатенацию строк. Сам оператор является строкой, переданной оптимизатору, который видит сравнение как правильные типы данных - от INT до INT.

Вы можете проверить и подтвердить самостоятельно, используя следующую информацию в Management Studio / Toad / etc:

DECLARE @course INT
    SET @course = 1234

SELECT 'Where course_id='+ @course

Это не удастся, с ошибкой чтения:

Сбой преобразования при преобразовании значения varchar 'где course_id =' в тип данных int.

... пока это:

DECLARE @course INT
    SET @course = 1234

SELECT 'Where course_id='+ CAST(@course AS VARCHAR) AS output

... вернет:

output
---------------------
Where course_id=1234

Существуют и другие способы приближения к динамическому SQL. Я настоятельно рекомендую прочитать эту статью - Проклятие и благословения динамического SQL - на тему .

1 голос
/ 10 ноября 2010

В вашем запросе вы на самом деле просто строите другой (динамический) запрос.Так, если у вас было, например:

SET @course = 2
SET @query = 'SELECT * FROM Courses'
SET @query = @query + 'Where course_id='+ cast(@course as varchar)

, значение @course преобразуется в символы, добавляется к @query и в конце концов:

SELECT * FROM Courses Where course_id=2

, что совершеннодействительный sql без необходимости что-либо преобразовывать перед выполнением.

1 голос
/ 10 ноября 2010

Вы, кажется, путаете сравнение (a = b) и назначение (SET @a = b)

При сравнении VARCHAR и INT первый всегда приводится к последнему, поэтому этот запрос не будет выполнен:

SELECT  1
WHERE   'ab' = 1

, поскольку 'ab' не может быть преобразовано в INT.

В назначении исходное значение (b) всегда приводится к типу цели (@a):

DECLARE @av VARCHAR(100)
SET     @av = 1
GO

DECLARE @ai INT
SET     @ai = 'ab'
GO

Поскольку INT всегда преобразуется в VARCHAR, первая партия всегда будет успешной, в отличие от второй, которая преобразует VARCHAR в INT.

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