我有一个选择 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 语句?

有帮助吗?

解决方案

因为查询中幕后操作的顺序无法保证。

我猜如果您检查执行计划,您会看到它并行执行这两项检查 - 这是因为这两个操作都不能使用索引!

无论如何,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。

其他提示

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

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 版本,可能会有多种“解决方案”。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top