我有一个语句选择charindex的子字符串,如下所示:
SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
WHERE
CHARINDEX('ABC', StringField) > 5
当我在select查询中运行上述语句时,结果返回正常。当我在模式绑定索引视图中运行上述语句时,我收到此错误:
Invalid length parameter passed to the LEFT or SUBSTRING function
为了解决这个问题,我将编写一个函数来获取CharIndex的Max和0以消除负值的可能性。但有谁知道为什么where子句不会过滤掉select语句?
答案 0 :(得分: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,因此引擎正在转换每一行。
答案 1 :(得分: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版本,可能会有几个“解决方案”。