SQL中的case语句,如何返回多个变量?

时间:2011-12-02 15:30:37

标签: sql sql-server

我想在我的case语句中返回多个值,例如:

SELECT
  CASE
    WHEN <condition 1> THEN <value1=a1, value2=b1>
    WHEN <condition 2> THEN <value1=a2, value2=b2>
    ELSE <value1=a3, value3=b3>
  END
FROM <table>

当然我可以多次编写案例条件,每次都返回一个值。但是,因为我有许多条件需要适合,比如说100.一次又一次地重复案例条件是不好的。

我想问的另一个问题,如果一条记录符合多个条件,会发生什么?这是否意味着它将返回所有这些或只是最后一个?例如条件1可能成为条件2的子集。会发生什么?

9 个答案:

答案 0 :(得分:13)

不幸的是,基本方法是重复自己。

SELECT
  CASE WHEN <condition 1> THEN <a1> WHEN <condition 2> THEN <a2> ELSE <a3> END,
  CASE WHEN <condition 1> THEN <b1> WHEN <condition 2> THEN <b2> ELSE <b3> END
FROM 
  <table> 

幸运的是,大多数RDBMS都足够聪明,不必多次评估条件。这只是多余的打字。


在MS SQL Server(2005+)中,您可以使用CROSS APPLY作为替代方法。虽然我不知道它是多么高效......

SELECT
  *
FROM
  <table>
CROSS APPLY
  (
   SELECT a1, b1 WHERE <condition 1>
   UNION ALL
   SELECT a2, b2 WHERE <condition 2>
   UNION ALL
   SELECT a3, b3 WHERE <condition 3>
  )
  AS case_proxy

这里明显的缺点是没有等效的ELSE,并且所有条件所有返回值,它们需要被框架化,以便一次只能有一个真实。


修改

如果Yuck的答案改为UNION而不是JOIN方法,那么它就变得非常相似了。然而,主要的区别在于,它只扫描输入数据集一次,而不是每个条件扫描一次(在您的情况下为100次)。


修改

我还注意到你可能意味着CASE语句返回的值是固定的。匹配相同条件的所有记录在value1和value2中获得完全相同的值。这可以像这样形成......

WITH
  checked_data AS
(
  SELECT
    CASE WHEN <condition1> THEN 1
         WHEN <condition2> THEN 2
         WHEN <condition3> THEN 3
         ...
         ELSE                   100
    END AS condition_id,
    *
  FROM
    <table>
)
,
  results (condition_id, value1, value2) AS
(
   SELECT 1, a1, b1
   UNION ALL
   SELECT 2, a2, b2
   UNION ALL
   SELECT 3, a3, b3
   UNION ALL
   ...
   SELECT 100, a100, b100
)
SELECT
  *
FROM
  checked_data
INNER JOIN
  results
    ON results.condition_id = checked_data.condition_id

答案 1 :(得分:6)

CASE语句只能返回一个值。

您可以将其转换为子查询,然后JOIN将其转换为您正在使用的其他关系。例如(使用SQL Server 2K5 + CTE):

WITH C1 AS (
  SELECT a1 AS value1, b1 AS value2
  FROM table
  WHERE condition1
), C2 AS (
  SELECT a2 AS value1, b2 AS value2
  FROM table
  WHERE condition2
), C3 AS (
  SELECT a3 AS value1, b3 AS value2
  FROM table
  WHERE condition3
)
SELECT value1, value2
FROM -- some table, joining C1, C2, C3 CTEs to get the cased values
;

答案 2 :(得分:6)

根据定义,

CASE仅返回单个值。如初。

它也(几乎总是)短路,这意味着如果满足您的第一个条件,则不会运行其他检查。

答案 3 :(得分:2)

在您的情况下,您将使用两个案例陈述,每个陈述用于您想要返回的每个值。

答案 4 :(得分:1)

或者您可以

SELECT
  String_to_array(CASE
    WHEN <condition 1> THEN a1||','||b1
    WHEN <condition 2> THEN a2||','||b2
    ELSE a3||','||b3
  END, ',') K
FROM <table>

答案 5 :(得分:0)

您可以使用与UNION结合的子选择。 每当您可以为多个条件返回相同的字段时,请使用括号中的OR,如下例所示:

SELECT * FROM
  (SELECT val1, val2 FROM table1 WHERE (condition1 is true) 
                                    OR (condition2 is true))
UNION
SELECT * FROM
  (SELECT val5, val6 FROM table7 WHERE (condition9 is true) 
                                    OR (condition4 is true))

答案 6 :(得分:0)

在SQL CASE子句中,应用第一个成功匹配的条件,并忽略任何后续匹配条件。

答案 7 :(得分:0)

您可以在“ case”表达式中的xml数据类型内返回多个值,然后将其提取,也可以使用“ else”块

SELECT 
xmlcol.value('(value1)[1]', 'NVARCHAR(MAX)') AS value1,
xmlcol.value('(value2)[1]', 'NVARCHAR(MAX)') AS value2
FROM
(SELECT CASE
WHEN <condition 1> THEN
CAST((SELECT a1 AS value1, b1 AS value2 FOR XML PATH('')) AS XML)
WHEN <condition 2> THEN
CAST((SELECT a2 AS value1, b2 AS value2 FOR XML PATH('')) AS XML)
ELSE
CAST((SELECT a3 AS value1, b3 AS value2 FOR XML PATH('')) AS XML)
END AS xmlcol
FROM <table>) AS tmp

答案 8 :(得分:0)

根据您的用例,可以使用多个select语句的并集,而不是使用case语句,每个条件一个。

当我发现此问题时,我的目标是有条件地选择多个列。我不一定需要案例陈述,所以这就是我所做的。

例如:

  SELECT
    a1,
    a2,
    a3,
    ...
  WHERE <condition 1>
    AND (<other conditions>)
  UNION
  SELECT
    b1,
    b2,
    b3,
    ...
  WHERE <condition 2>
    AND (<other conditions>)
  UNION
  SELECT
  ...
-- and so on

请确保一次一次恰好满足一个条件。

我正在使用Postgresql,并且查询计划程序非常聪明,即使where子句中的条件评估为false(即实际上只有一条select语句在运行),它也根本不会运行select语句。对我来说很表现。