Tom*_*ski 4 sql t-sql sql-server-2005 query-optimization
我有一个带有BigMacs nvarchar(255)列的MS SQL表McTable.我想获得BigMacs值大于5的行.
我所做的是:
select * from
(
select
BigMacs BigMacsS,
CAST(BigMacs as Binary) BigMacsB,
CAST(BigMacs as int) BigMacsL
from
McTable
where
BigMacs Like '%[0-9]%'
) table
where
Cast(table.BigMacsL as int) > 5
Run Code Online (Sandbox Code Playgroud)
结果我得到一个错误:
将nvarchar值'***'转换为数据类型int时,状态1,行67转换失败.
但当我删除最后一个过滤器时,where Cast(table.BigMacsL as int) > 5
它可以工作,我得到这个结果:
6 0x360000000000000000000000000000000000000000000000000000000000 6 23 0x320033000000000000000000000000000000000000000000000000000000 23 22 0x320032000000000000000000000000000000000000000000000000000000 22 24 0x320034000000000000000000000000000000000000000000000000000000 24 25 0x320035000000000000000000000000000000000000000000000000000000 25 3 0x330000000000000000000000000000000000000000000000000000000000 3 17 0x310037000000000000000000000000000000000000000000000000000000 17 17 0x310037000000000000000000000000000000000000000000000000000000 17 19 0x310039000000000000000000000000000000000000000000000000000000 19 20 0x320030000000000000000000000000000000000000000000000000000000 20 659 0x360035003900000000000000000000000000000000000000000000000000 659 1 0x310000000000000000000000000000000000000000000000000000000000 1 43 0x340033000000000000000000000000000000000000000000000000000000 43 44 0x340034000000000000000000000000000000000000000000000000000000 44 45 0x340035000000000000000000000000000000000000000000000000000000 45 46 0x340036000000000000000000000000000000000000000000000000000000 46 47 0x340037000000000000000000000000000000000000000000000000000000 47 44 0x340034000000000000000000000000000000000000000000000000000000 44 44 0x340034000000000000000000000000000000000000000000000000000000 44 47 0x340037000000000000000000000000000000000000000000000000000000 47 43 0x340033000000000000000000000000000000000000000000000000000000 43 50 0x350030000000000000000000000000000000000000000000000000000000 50 44 0x340034000000000000000000000000000000000000000000000000000000 44
当我将第一个查询'select*from'更改为'select top 18*from'时,我也没有得到错误!
我不知道是什么问题,以及如何使它工作!请你帮助我好吗?
再一次:我在这里尝试完成的是获取BigMacs值大于5的McTable行.
UPDATE
重现此错误的步骤:
我已准备好查询,因此您可以轻松地在数据库中出现此错误:
创建数据库TestDB,使用以下命令创建表:
USE [TestDB]
GO
/****** Object: Table [dbo].[TestTable] Script Date: 04/08/2009 16:27:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TestTable](
[ID] [int] IDENTITY(1,1) NOT NULL,
[MyVal] [nvarchar](255) COLLATE Polish_CI_AS NOT NULL,
CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
插入值:
delete from TestDB.dbo.TestTable
insert into TestDB.dbo.TestTable (MyVal) values ('fd')
insert into TestDB.dbo.TestTable (MyVal) values ('54543534')
insert into TestDB.dbo.TestTable (MyVal) values ('fat3tv3gv5')
insert into TestDB.dbo.TestTable (MyVal) values ('fdf4v43 4v434v')
insert into TestDB.dbo.TestTable (MyVal) values (' g dfg dfg df')
insert into TestDB.dbo.TestTable (MyVal) values ('f sd 4t4gsdf')
insert into TestDB.dbo.TestTable (MyVal) values ('f df 4 trwefg')
insert into TestDB.dbo.TestTable (MyVal) values ('f sd f4 fgsfg sd')
insert into TestDB.dbo.TestTable (MyVal) values ('54534534')
insert into TestDB.dbo.TestTable (MyVal) values ('454')
Run Code Online (Sandbox Code Playgroud)
这个查询:
select
CAST(MyVal as int) MyValInt
from
dbo.TestTable
where
IsNumeric(MyVal) = 1
Run Code Online (Sandbox Code Playgroud)
得到有效数字,如下所示:
54543534
54534534
454
当您尝试使用此查询获取过滤值时:
select
*
from
(
select
CAST(MyVal as int) MyValInt
from
dbo.TestTable
where
IsNumeric(MyVal) = 1
) tabela
where
tabela.MyValInt > 6
Run Code Online (Sandbox Code Playgroud)
您应该收到不应发生的错误:
消息245,级别16,状态1,行1转换将nvarchar值'fd'转换为数据类型int时失败.
修改过的脚本的新答案.发生的事情是SQL Server查询优化器正在优化您的子查询.它正在执行测试表的单次扫描,并将内部和外部WHERE子句合并为一个.这就是为什么你仍然得到错误.要查看此信息,请查看查询的估计执行计划,并将鼠标悬停在"聚集索引扫描"图标上以查看实际执行的内容.您将在扫描中看到以下谓词:
CONVERT(int,[testdb].[dbo].[TestTable].[MyVal],0)>(6)
AND isnumeric(CONVERT_IMPLICIT(varchar(510),
[testdb].[dbo].[TestTable].[MyVal],0))=(1)
Run Code Online (Sandbox Code Playgroud)
因此,无论您的查询结构如何,它都会尝试在表中的每一行上执行CAST/CONVERT ...
要避免这种情况,请使用无法优化的表变量或临时表:
DECLARE @integers table (
MyValInt int
)
INSERT
INTO @integers
SELECT CAST(MyVal AS int)
FROM dbo.TestTable
WHERE ISNUMERIC(MyVal) = 1
SELECT *
FROM @integers
WHERE MyValInt > 6
Run Code Online (Sandbox Code Playgroud)
您实际想要返回的结果集将是不同的,因此我建议将主键与int值一起存储在表变量中,然后将最终查询作为连接执行,如下所示:
DECLARE @integers table (
ID int,
MyValInt int
)
INSERT
INTO @integers
SELECT ID, CAST(MyVal AS int)
FROM dbo.TestTable
WHERE ISNUMERIC(MyVal) = 1
SELECT b.*
FROM @integers t
INNER JOIN
TestTable b
ON b.ID = t.ID
WHERE t.MyValInt > 6
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
6583 次 |
最近记录: |