关于sql server:如何在SQL SELECT中执行IF … THEN?

关于sql server:如何在SQL SELECT中执行IF … THEN?

How do I perform an IF…THEN in an SQL SELECT?

我如何执行在IF...THENSQL SELECT语句?

例如:

1
SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product

CASE语句是SQL中最接近if的语句,所有版本的SQL Server都支持该语句。

1
2
3
4
5
6
7
SELECT CAST(
             CASE
                  WHEN Obsolete = 'N' OR InStock = 'Y'
                     THEN 1
                  ELSE 0
             END AS bit) AS Saleable, *
FROM Product

如果希望结果为布尔值,则只需执行CAST。如果你对int满意,这就可以:

1
2
3
4
5
6
SELECT CASE
            WHEN Obsolete = 'N' OR InStock = 'Y'
               THEN 1
               ELSE 0
       END AS Saleable, *
FROM Product

CASE语句可以嵌入到其他CASE语句中,甚至包括在聚合中。

SQL Server Denali(SQL Server 2012)添加了IIF语句,该语句在Access中也可用(由Martin Smith指出):

1
SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Saleable, * FROM Product


案例陈述是您在这种情况下的朋友,采用两种形式之一:

简单的例子:

1
2
3
4
5
SELECT CASE <variable> WHEN <value>      THEN <returnvalue>
                       WHEN <othervalue> THEN <returnthis>
                                         ELSE <returndefaultcase>
       END AS <newcolumnname>
FROM <table>

扩展案例:

1
2
3
4
5
SELECT CASE WHEN <test>      THEN <returnvalue>
            WHEN <othertest> THEN <returnthis>
                             ELSE <returndefaultcase>
       END AS <newcolumnname>
FROM <table>

您甚至可以将case语句放在order by子句中,以便进行真正奇特的排序。


在SQL Server 2012中,您可以使用IIF函数来实现这一点。

1
2
SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM   Product

这实际上只是编写CASE的一种简写方式(尽管不是标准的SQL)。

与扩展的CASE版本相比,我更喜欢简洁。

IIF()CASE都在SQL语句中解析为表达式,只能在定义良好的地方使用。

The CASE expression cannot be used to control the flow of execution of
Transact-SQL statements, statement blocks, user-defined functions, and
stored procedures.

如果这些限制不能满足您的需求(例如,需要根据某些条件返回不同形状的结果集),那么SQL Server也有一个过程性的IF关键字。

1
2
3
4
5
6
7
8
9
10
IF @IncludeExtendedInformation = 1
  BEGIN
      SELECT A,B,C,X,Y,Z
      FROM   T
  END
ELSE
  BEGIN
      SELECT A,B,C
      FROM   T
  END

但是,有时必须小心避免使用这种方法时出现参数嗅探问题。


您可以在SQL case语句的强大功能中找到一些很好的示例,我认为您可以使用的语句如下(来自4Guysfromrolla):

1
2
3
4
5
6
7
8
SELECT
    FirstName, LastName,
    Salary, DOB,
    CASE Gender
        WHEN 'M' THEN 'Male'
        WHEN 'F' THEN 'Female'
    END
FROM Employees


用例。像这样。

1
2
3
4
5
SELECT Salable =
        CASE Obsolete
        WHEN 'N' THEN 1
        ELSE 0
    END


1
2
3
4
5
6
7
SELECT  
(CASE
     WHEN (Obsolete = 'N' OR InStock = 'Y') THEN 'YES'
                                            ELSE 'NO'
 END) AS Salable
, *
FROM Product

1
2
3
4
5
6
7
 SELECT
   CASE
      WHEN OBSOLETE = 'N' OR InStock = 'Y' THEN 'TRUE'
      ELSE 'FALSE'
   END AS Salable,
   *
FROM PRODUCT

Microsoft SQL Server(T-SQL)

select中,使用:

1
SELECT CASE WHEN Obsolete = 'N' OR InStock = 'Y' THEN 'YES' ELSE 'NO' END

where条款中,使用:

1
WHERE 1 = CASE WHEN Obsolete = 'N' OR InStock = 'Y' THEN 1 ELSE 0 END


通过这个链接,我们可以理解T-SQL中的IF THEN ELSE

1
2
3
4
5
6
7
8
9
10
11
12
13
IF EXISTS(SELECT *
          FROM   Northwind.dbo.Customers
          WHERE  CustomerId = 'ALFKI')
  PRINT 'Need to update Customer Record ALFKI'
ELSE
  PRINT 'Need to add Customer Record ALFKI'

IF EXISTS(SELECT *
          FROM   Northwind.dbo.Customers
          WHERE  CustomerId = 'LARSE')
  PRINT 'Need to update Customer Record LARSE'
ELSE
  PRINT 'Need to add Customer Record LARSE'

这对T-SQL来说还不够好吗?


SQL Server中的简单if-else语句:

1
2
3
4
5
6
7
8
9
DECLARE @val INT;
SET @val = 15;

IF @val < 25
PRINT 'Hi Ravi Anand';
ELSE
PRINT 'By Ravi Anand.';

GO

SQL Server中嵌套的if…else语句-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DECLARE @val INT;
SET @val = 15;

IF @val < 25
PRINT 'Hi Ravi Anand.';
ELSE
BEGIN
IF @val < 50
  PRINT 'what''s up?';
ELSE
  PRINT 'Bye Ravi Anand.';
END;

GO


使用纯位逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
DECLARE @Product TABLE (
    id INT PRIMARY KEY IDENTITY NOT NULL
   ,Obsolote CHAR(1)
   ,Instock CHAR(1)
)

INSERT INTO @Product ([Obsolote], [Instock])
    VALUES ('N', 'N'), ('N', 'Y'), ('Y', 'Y'), ('Y', 'N')

;
WITH cte
AS
(
    SELECT
        'CheckIfInstock' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Instock], 'Y'), 1), 'N'), 0) AS BIT)
       ,'CheckIfObsolote' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Obsolote], 'N'), 0), 'Y'), 1) AS BIT)
       ,*
    FROM
        @Product AS p
)
SELECT
    'Salable' = c.[CheckIfInstock] & ~c.[CheckIfObsolote]
   ,*
FROM
    [cte] c

请参见工作演示:如果没有,则SQL Server中的CASE

首先,您需要计算所选条件下的truefalse的值。以下是两个零位:

1
2
FOR TRUE: ISNULL(NULLIF(p.[Instock], 'Y'), 1)
FOR FALSE: ISNULL(NULLIF(p.[Instock], 'N'), 0)

加在一起得到1或0。接下来使用位运算符。

这是最WYSIWYG的方法。


在SQL Server 2012中添加了一个新功能iif(我们可以简单地使用它):

1
SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product

使用案例陈述:

1
2
3
4
5
6
7
SELECT CASE
       WHEN (Obsolete = 'N' OR InStock = 'Y')
       THEN 'Y'
       ELSE 'N'
END AS Available

etc...

1
2
3
4
5
6
7
SELECT 1 AS Saleable, *
  FROM @Product
 WHERE ( Obsolete = 'N' OR InStock = 'Y' )
UNION
SELECT 0 AS Saleable, *
  FROM @Product
 WHERE NOT ( Obsolete = 'N' OR InStock = 'Y' )


1
2
SELECT CASE WHEN profile.nrefillno = 0 THEN 'N' ELSE 'R'END AS newref
FROM profile


1
2
3
4
5
6
7
8
CASE statement SOME what SIMILAR TO IF IN SQL server

SELECT CASE
            WHEN Obsolete = 'N' OR InStock = 'Y'
               THEN 1
               ELSE 0
       END AS Saleable, *
FROM Product

这不是答案,只是在我工作的地方使用的一个案例陈述的例子。它有一个嵌套的case语句。现在你知道为什么我的眼睛是交叉的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 CASE orweb2.dbo.Inventory.RegulatingAgencyName
    WHEN 'Region 1'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
    WHEN 'Region 2'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
    WHEN 'Region 3'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
    WHEN 'DEPT OF AGRICULTURE'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactAg
    ELSE (
            CASE orweb2.dbo.CountyStateAgContactInfo.IsContract
                WHEN 1
                    THEN orweb2.dbo.CountyStateAgContactInfo.ContactCounty
                ELSE orweb2.dbo.CountyStateAgContactInfo.ContactState
                END
            )
    END AS [County Contact Name]


如果您是第一次将结果插入到表中,而不是将结果从一个表传输到另一个表中,这在Oracle 11.2g中有效:

1
2
3
4
5
6
7
INSERT INTO customers (last_name, first_name, city)
    SELECT 'Doe', 'John', 'Chicago' FROM dual
    WHERE NOT EXISTS
        (SELECT '1' FROM customers
            WHERE last_name = 'Doe'
            AND first_name = 'John'
            AND city = 'Chicago');


作为CASE语句的替代解决方案,可以使用表驱动方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DECLARE @Product TABLE (ID INT, Obsolete VARCHAR(10), InStock VARCHAR(10))
INSERT INTO @Product VALUES
(1,'N','Y'),
(2,'A','B'),
(3,'N','B'),
(4,'A','Y')

SELECT P.* , ISNULL(Stmt.Saleable,0) Saleable
FROM
    @Product P
    LEFT JOIN
        ( VALUES
            ( 'N', 'Y', 1 )
        ) Stmt (Obsolete, InStock, Saleable)
        ON  P.InStock = Stmt.InStock OR P.Obsolete = Stmt.Obsolete

结果:

1
2
3
4
5
6
ID          Obsolete   InStock    Saleable
----------- ---------- ---------- -----------
1           N          Y          1
2           A          B          0
3           N          B          1
4           A          Y          1


1
2
3
SELECT CASE WHEN Obsolete = 'N' OR InStock = 'Y' THEN 1 ELSE 0
             END AS Saleable, *
FROM Product

1
  SELECT IIF(Obsolete = 'N' OR InStock = 'Y',1,0) AS Saleable, * FROM Product

对于那些使用SQL Server 2012的用户,IIF是一个已经添加的功能,可以作为case语句的替代。

1
2
SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM   Product


您可以有两种选择来实际实现:

  • 使用从SQL Server 2012引入的IIF:

    1
    SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
  • 使用Select Case

    1
    2
    3
    4
    5
    6
    SELECT CASE
        WHEN Obsolete = 'N' OR InStock = 'Y'
            THEN 1
            ELSE 0
        END AS Saleable, *
        FROM Product


  • 问题:

    1
    SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product

    美国国家标准协会:

    1
    2
    3
    4
    5
    6
    SELECT
      CASE WHEN p.Obsolete = 'N'
      OR p.InStock = 'Y' THEN 1 ELSE 0 END AS Saleable,
      p.*
    FROM
      Product p;

    使用别名(在本例中为p)将有助于防止出现问题。


    1
    2
    3
    4
    5
    6
    7
    SELECT
      CAST(
        CASE WHEN Obsolete = 'N'
        OR InStock = 'Y' THEN ELSE 0 END AS bit
      ) AS Saleable, *
    FROM
      Product

    推荐阅读