使用IN时不允许多个CASE子查询结果

时间:2016-12-01 18:56:53

标签: sql-server tsql subquery case

我正在使用以下查询:

SELECT *
FROM TableA a
WHERE a.FieldA IN (

    CASE

    --select subquery returns a single value
    WHEN a.FieldB = 'Value1'
        THEN (select b.ID from TableB b where b.FK_Field = '123')

    --select subquery returns multiple values
    WHEN a.FieldB = 'Value2'
        THEN (select c.ID from TableC c where c.FK_Field = '123')

    END
)

第一个case select语句只返回一个b.ID。如果我有这个陈述,我的代码就可以了。

然而,第二个case语句返回多个c.ID s。当我添加该检查时,我收到以下错误:

  

子查询返回的值超过1。这是不允许的   子查询跟随=,!=,<,< =,>,> =或当子查询用作   表达。

如果我有WHERE a.FieldA =,那么我理解子查询只能返回1个值。但是我有WHERE a.FieldA IN,那么为什么如果有多个值返回会抱怨?

我该如何实施这种检查?

3 个答案:

答案 0 :(得分:1)

正如@marc_s在评论中解释的那样:

  

T-SQL中的CASE是一个返回单个表达式的表达式(如a + b),   原子值 - 您不能使用它来有选择地运行那些SQL片段   返回整个结果集

为了解决此错误,我删除了CASE语句,而是使用了一堆ANDOR语句来完成相同类型的检查。

SELECT *
FROM TableA a
WHERE
    (a.FieldB = 'Value1'
        AND a.FieldA IN (select b.ID from TableB b where b.FK_Field = '123'))

    OR (a.FieldB = 'Value2'
        AND a.FieldA IN (select c.ID from TableC c where c.FK_Field = '123'))

这段代码比CASE语句有点麻烦,但它有效。

答案 1 :(得分:1)

这样做的方法很多,这里是使用union all和相关EXISTS语句的一种方法

;WITH cte AS (
    SELECT 'Value1' as FieldB, b.Id
    FROM
       TableB
    WHERE
       b.FK_FieldId = '123'

    UNION ALL

    SELECT 'Value1' as FieldB, c.Id
    FROM
       TableB
    WHERE
       c.FK_FieldId = '123'
)



SELECT *
FROM
    TableA a
WHERE
    EXISTS (SELECT 1
          FROM
             cte c
          WHERE
             a.FieldB = c.FieldB
             AND a.FieldA = c.Id)

你编写它的方式的问题是你得到一个非标量值(意思是超过1行),其中sql期望一个标量值。在case表达式中,只有标量值可以在THEN部分中使用,也可以在WHEN中使用一些规则。要解决此问题,您需要将case表达式拆分为多个where语句和/或使用其他一些技术,例如上面的那些。

或者您可以像这样编写案例表达式:

SELECT *
FROM
    TableA a
WHERE
    (CASE
       WHEN a.FieldB = 'Value1' AND a.FieldA IN (select b.ID from TableB b where b.FK_Field = '123') THEN 1
       WHEN a.FieldB = 'Value2' AND a.FieldA IN (select c.ID from TableC c where c.FK_Field = '123') THEN 1
       ELSE 0
    END) = 1

答案 2 :(得分:0)

如果没有必要,请不要在谓词中使用case - 使用case使你的参数non-SARG(你不会使用索引)。

SELECT *
FROM TableA a
WHERE EXISTS(
        SELECT NULL 
        FROM TableB b 
        WHERE a.FieldB = 'Value1' 
            AND b.FK_Field = '123' 
            AND a.FieldA = b.ID))
    OR EXISTS(
        SELECT NULL 
        FROM TableC c 
        WHERE a.FieldB = 'Value2' 
            AND c.FK_Field = '123' 
            AND a.FieldB = c.ID))

使用索引。并尝试让你的qry可读。

或者,如果您想使用半连接:

SELECT *
FROM TableA a
WHERE a.FieldA IN (
        SELECT b.ID
        FROM TableB b 
        WHERE a.FieldB = 'Value1' 
            AND b.FK_Field = '123'))
    OR a.FieldB IN (
        SELECT c.ID
        FROM TableC c 
        WHERE a.FieldB = 'Value2' 
            AND c.FK_Field = '123'))

这两种解决方案均适用于SARG。