SQL Server,其中子句与不同类型和默认转换行为进行比较

Eoi*_*ell 5 sql sql-server types casting

对吧......这个让我困惑了一会儿,所以也许你们其中一个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
Run Code Online (Sandbox Code Playgroud)

第一个选择(标记为#1)将起作用第二个选择(标记为#2)将起作用但在第三个选择(标记为#3)后不会立即返回错误.

返回的错误是

Error converting data type nvarchar to bigint.
Run Code Online (Sandbox Code Playgroud)

现在这似乎完全是疯子的行为.我认为会发生什么

  1. SQL实现了它在WHERE子句中比较2种不同的数据类型
  2. 它会尝试将@variable转换为列的数据类型
  3. 如果它失败了,抛出一个错误,它的工作原理,太棒了!

实际上似乎正在发生的是

  1. SQL实现了它在WHERE子句中比较2种不同的数据类型
  2. 在逐行的基础上,它将列中的值转换为@variable的数据类型
  3. 对于每次成功转换,它都会进行比较,并返回该行.
  4. 如果它命中列中的值,它无法转换,它会发出炸弹,返回它到目前为止找到的任何数据,并且不会继续通过表.

任何人都可以澄清这个逻辑背后的原因是什么,以及SQL Server在决定比较/转换时给予数据类型的任何特定优先顺序

注意.我在SQL 2005中进行了这个测试,但它在SQL2K中也是可复制的行为.

aha*_*ins 4

数据类型优先级定义明确 - http://msdn.microsoft.com/en-us/library/ms190309.aspx

编辑-澄清一下,sql并不总是将列类型转换为参数类型。它只是遵循我给出的链接中的类型优先级。这可能意味着参数将转换为列类型(如果类型优先级指定的话)。