由于外部WHERE

时间:2015-08-13 09:46:58

标签: sql sql-server

不要问我为什么要这样做或者我试图解决什么问题。由于多方等情况,我们遇到了这个错误 - 我认为这可能是SQL Server中的一个错误。请不要给我提供替代解决方案,我只是想了解为什么这个特殊情况会失败。

我有一张桌子:

CREATE TABLE T (Id NVARCHAR(50))

使用以下条目:

INSERT INTO T(Id) VALUES
    (NULL),
    ('45B7522C-248E-48A9-92B2-BC164C5F58EC'),
    ('usr://fed/45B7522C-248E-48A9-92B2-BC164C5F58EC')

我在这个表上有一个视图/子查询(两者都给出相同的结果):

SELECT * FROM (
    SELECT CONVERT(UNIQUEIDENTIFIER, Id) AS Id_Converted
    FROM T
    WHERE Id LIKE '________-____-____-____-____________'
) V
WHERE Id_Converted = '45B7522C-248E-48A9-92B2-BC164C5F58EC'

此操作失败并显示以下消息:

Conversion failed when converting from a character string to uniqueidentifier.

我希望在WHERE语句之后使用内部UNIQUEIDENTIFIER(仅选择可以转换为CONVERT的记录)外WHERE。我知道SQL Server将首先使用WHERE语句获取匹配的记录,但在这种情况下,除非Id字段转换为UNIQUEIDENTIFIER,否则不应使用外部WHERE。 如果没有这个外部WHERE语句,子查询就可以正常工作。

对此有何想法?

对于那些感兴趣的人,解决方法可能是使用这个SELECT语句:

SELECT
    CASE
        WHEN Id LIKE '________-____-____-____-____________'
        THEN CONVERT(UNIQUEIDENTIFIER, Id) 
        ELSE NULL
    END AS Id_Converted

1 个答案:

答案 0 :(得分:2)

这是因为查询优化器将子查询和外部查询折叠为具有以下条件的单个表扫描:

CONVERT(uniqueidentifier,T.Id,0)={guid'45B7522C-248E-48A9-92B2-BC164C5F58EC'} AND T.Id like N'________-____-____-____-____________'

(您可以通过显示执行计划来看到这一点)。我可以做的最好的办法是阻止查询优化器执行此操作,使子查询成为(索引,模式绑定)视图,然后允许使用NOEXPAND表提示:

CREATE VIEW dbo.V
with schemabinding
AS
    SELECT CONVERT(UNIQUEIDENTIFIER, Id) AS Id_Converted
    FROM dbo.T
    WHERE Id LIKE '________-____-____-____-____________';
GO

create unique clustered index V_idx1 on V (Id_Converted);
GO

SELECT * FROM  V with (noexpand)
WHERE Id_Converted = '45B7522C-248E-48A9-92B2-BC164C5F58EC'

但你可能更喜欢你的解决方法!