3

我有一个语句选择 charindex 的子字符串,如下所示:

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
WHERE 
CHARINDEX('ABC', StringField) > 5

当我在选择查询中运行上述语句时,结果返回得很好。当我在模式绑定索引视图中运行上述语句时,我收到此错误:

Invalid length parameter passed to the LEFT or SUBSTRING function

为了解决这个问题,我将编写一个函数来获取 CharIndex 的最大值和 0,以消除负值的可能性。但是有谁知道为什么 where 子句不会过滤掉 select 语句?

4

2 回答 2

2

因为不能保证查询中幕后的操作顺序。

我猜如果你检查执行计划,你会看到它同时进行了两项检查——这是因为这两个操作都不能使用索引!

SQL 无论如何都需要将该字段的每一行加载到内存中,因此它同时针对这两个条件进行处理。

您可以尝试WITH (MAXDOP(1))作为查询提示来查看是否会阻止问题出现,或者您可以执行子选择来强制执行顺序:

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
FROM (
      SELECT Stringfield 
      FROM Table 
      WHERE CHARINDEX('ABC', StringField) > 5
      ) as [X]

当我检查一个字段是否为数字使用时,我遇到了类似的问题,PATINDEX并且我的视图中的一列正在将其转换为int- 我遇到转换错误,因为引擎正在转换每一行,因为我的过滤器不是 SARGable。

于 2012-02-24T16:57:35.270 回答
1

这是一个丑陋的解决方法,但您也许可以这样做:

DECLARE @x TABLE(StringField VARCHAR(32));

INSERT @x SELECT 'ABC'
UNION ALL SELECT 'A'
UNION ALL SELECT 'AAAAAAAABC';

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;

SELECT SUBSTRING(StringField,
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 1 END,
    CHARINDEX('ABC', StringField) - 
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 0 END)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;

两者都产生:

---
AAA

但我怀疑你认为后者会被允许。这很丑陋,但不幸的是,除非您首先将过滤后的数据转储到 #temp 表(或尝试查看是否MAXDOP可靠地消除了问题),否则您将无法控制处理顺序。

另一个想法是尝试将计算列放入表中(但我不确定如果您尝试创建索引视图会有所帮助 - 可能仍然存在并发症)。或者使用带有该表达式的过滤索引,而不是索引视图。如果我们知道索引视图的目的是什么以及您使用的是什么版本的 SQL Server,那么可能有几个“解决方案”。

于 2012-02-24T17:17:38.090 回答