Правильно ... сегодня меня это озадачило, так что, может быть, один из ярких искр SQL Server может пролить свет на это поведение.
У нас есть стол Phones
. В нем телефонные номера хранятся как nvarchars, и он содержит номера в международном формате, только в числовом формате ... поэтому номер США +1-(212)-999-9999
хранится как 12129999999
По не зависящим от меня причинам, кто-то написал SPROC, который взял номер телефона как bigint, не делал кастинг, делал простое выражение where = сравнение, и это работало абсолютно нормально, пока некоторые ненужные данные не попали в Столбец nvarchar на столе, который заставил его сломаться. Рассмотрим следующий тестовый скрипт.
IF EXISTS (SELECT * FROM sys.tables WHERE name = 'Phones')
BEGIN
DROP TABLE Phones
END
GO
CREATE TABLE [dbo].[Phones]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Mobile] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Phones] PRIMARY KEY CLUSTERED
( [ID] ASC )
WITH (
PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]
) ON [PRIMARY]
GO
DECLARE @biMobile_1 bigint
DECLARE @biMobile_2 bigint
SET @biMobile_1 = 12121111111
SET @biMobile_2 = 12129999999
Print 'Inserting Phone Number'
INSERT INTO Phones (Mobile) VALUES ('12121111111')
Print 'Selecting Phone Number'
SELECT * FROM Phones WHERE Mobile = @biMobile_1 --Select #1
Print 'Inserting Junk Data'
INSERT INTO Phones (Mobile) VALUES ('JUNK DATA')
INSERT INTO Phones (Mobile) VALUES ('12129999999')
Print 'Selecting From Table Containing Junk'
SELECT * FROM Phones WHERE Mobile = @biMobile_1 -- Select #2
SELECT * FROM Phones WHERE Mobile = @biMobile_2 -- Select #3
Первый выбор (помеченный # 1) будет работать
Второй выбор (помеченный # 2) будет работать, но сразу же выдаст ошибку
Третий выбор (помеченный # 3) ничего не возвращает.
Ошибка:
Error converting data type nvarchar to bigint.
Теперь это выглядит совершенно помешанным. Я думал, что это произойдет, это
- SQL реализует сравнение двух разных типов данных в предложении
WHERE
- Будет предпринята попытка преобразовать @variable в тип данных столбца
- Если не получится, выведите ошибку, это работает, ОТЛИЧНО !!!
То, что на самом деле происходит, это
- SQL реализует сравнение двух разных типов данных в предложении
WHERE
- Построчно он преобразует значение в столбце в тип данных переменной @ 1033 *
- Для каждого успешного преобразования он выполняет сравнение и возвращает эту строку.
- Если он попадает в значение в столбце, которое он не может преобразовать, он бомбардирует, возвращает все найденные данные и не перебирает таблицу.
Может ли кто-нибудь уточнить, что за логика стоит за этой логикой, и если есть какой-либо конкретный порядок приоритета, который SQL Server дает типам данных, когда он решает, что сравнивать / приводить
Примечание. Я провел этот тест в SQL 2005, но в SQL2K он также воспроизводим.