T-SQL。 CTE和IN子句。转换失败

时间:2017-10-04 13:37:20

标签: sql-server tsql common-table-expression

假设我们有下一个t-SQL代码:

;WITH [CTE] AS
(
    SELECT 0 [A], 'FAULT' [B]
    UNION ALL
    SELECT 1 [A], '1' [B]
    UNION ALL
    SELECT 2 [A], '2' [B]
),
[CTE2] AS
(
    SELECT [B]
    FROM [CTE]
    WHERE [A] > 0
)
SELECT * FROM [CTE2]
WHERE 1 IN (SELECT [B] FROM [CTE2])

此代码出现错误:

  

“将varchar值'FAULT'转换为数据类型int时转换失败。”

CTE只是准备数据。 CTE2过滤数据,因此它应该返回两个记录,其中[B] ='1'和[B] ='2'。 然后在IN子句中使用CTE2。 1是整数。因此(SELECT [Value] FROM [CTE2])的结果必须转换为Integer。

为什么尝试将字符串'FAULT'转换为Integer? CTE2不会返回此字符串。

3 个答案:

答案 0 :(得分:0)

怎么样:

;WITH [CTE] AS
(
    SELECT 0 [A], 'FAULT' [B]
    UNION ALL
    SELECT 1 [A], '1' [B]
    UNION ALL
    SELECT 2 [A], '2' [B]
)
SELECT * FROM [CTE]
WHERE [A] > 0
AND [B] = '1'

输出

A   B
1   1

SQL小提琴:http://sqlfiddle.com/#!6/9eecb7db59d16c80417c72d1e1f4fbf1/7630/0

答案 1 :(得分:0)

你可以使用类似的东西:

WITH [CTE] AS
(
SELECT 0 [A], 'FAULT' [B]
UNION ALL
SELECT 1 [A], '1' [B]
UNION ALL
SELECT 2 [A], '2' [B]
),
[CTE2] AS
(
SELECT [B]
FROM [CTE]
WHERE [A] > '0'
)
SELECT * FROM [CTE2]
WHERE 1 IN (SELECT [B] FROM [CTE2] WHERE CASE WHEN ISNUMERIC([B]) = 1 THEN 1 ELSE 0 END = 1)

答案 2 :(得分:0)

这是type precedence的问题:

  

当运算符组合了两个不同数据类型的表达式时,数据类型优先级的规则指定优先级较低的数据类型转换为具有较高优先级的数据类型。

     

16.int

     

27.varchar

所以int“胜利”。但是FAULT不是有效的int值。您可以使用显式强制转换:

;WITH [CTE] AS
(
    SELECT 0 [A], 'FAULT' [B]
    UNION ALL
    SELECT 1 [A], '1' [B]
    UNION ALL
    SELECT 2 [A], '2' [B]
),
[CTE2] AS
(
    SELECT [B]
    FROM [CTE]
    WHERE [A] > 0
)
SELECT * FROM [CTE2]
WHERE CAST(1 AS VARCHAR(10)) IN (SELECT [B] FROM [CTE2]);

<强> Rextester Demo

请注意构造:

SELECT * FROM [CTE2]
WHERE 1 IN (SELECT [B] FROM [CTE2])
如果[B]不为空并且1已设置,

将返回所有行。