为什么一个SQL查询工作而另一个不工作?

时间:2017-10-26 13:20:01

标签: sql sql-server-2012

请忽略where子句中操作数据的明显问题。我知道!我在做这个工作。但是,在进行此操作时,我发现此查询运行:

SELECT *
FROM PatientDistribution
WHERE InvoiceNumber LIKE'PEX%'
AND ISNUMERIC(CheckNumber) = 1
AND CONVERT(BIGINT,CheckNumber) <> TransactionId

这个不是:

SELECT *
FROM PatientDistribution
WHERE InvoiceNumber LIKE'PEX%'
AND CONVERT(BIGINT,CheckNumber) <> TransactionId
AND ISNUMERIC(CheckNumber) = 1

两个查询之间的唯一区别是WHERE子句中的项目顺序。我的印象是SQL Server查询优化器会让我担心不必担心这一点。

返回的错误是:将数据类型varchar转换为bigint时出错。

2 个答案:

答案 0 :(得分:1)

你是对的,条件的顺序无关紧要。

  • 如果首先检查AND ISNUMERIC(CheckNumber) = 1并且因此解除了不匹配的行,那么AND CONVERT(BIGINT,CheckNumber) <> TransactionId将起作用(对于例外情况,请参阅scsimon的答案)。
  • 如果在AND CONVERT(BIGINT,CheckNumber) <> TransactionId之前处理AND ISNUMERIC(CheckNumber) = 1,则可能会收到错误。

你的第一个查询有效,第二个查询不是运气问题。反过来也可以这样。

您可以强制一个条件在另一个条件之前执行:

SELECT *
FROM 
(
  SELECT *
  FROM PatientDistribution
  WHERE InvoiceNumber LIKE 'PEX%'
  AND ISNUMERIC(CheckNumber) = 1
) num_only
WHERE CONVERT(BIGINT,CheckNumber) <> TransactionId;

答案 1 :(得分:0)

你很幸运第一个工作,因为你是正确的,你在where子句中列出的顺序无关紧要。 SQL是一种声明性语言,意味着您告诉引擎应该发生什么,而不是如何。因此,您的查询并未使用我怀疑的相同查询计划执行。当然,您可以在一定程度上影响优化器的功能。使用CTE时,您还会注意到此类问题。例如:

declare @table table(columnName varchar(64))
insert into @table
values
('1')
,('1e4')

;with cte as(
select columnName
from @table
where isnumeric(columnName) = 1)

select
cast(columnName as decimal(32,16))
from cte

上面的代码片段假设第二个语句是在CTE语句的结果/子集上运行的。但是,您无法确保这种情况发生,并且您仍然可能在第二个语句上遇到类型/转换错误。

更重要的是,您应该知道ISNUMERIC()在很大程度上被误用了。人们通常认为如果它返回1则可以转换为小数或int。但事实并非如此。它只是检查它是否是有效的数字类型。例如:

select 
   isnumeric('1e4')
   ,isnumeric('$')
   ,isnumeric('1,123,456')

正如您所看到的,这些评估为true,但会使您在帖子中的转化失败。

旁注,您的索引可能是第一个实际上没有错误的原因。