3

我有一个 SQLExpress 表,其中包含一个用于存储 TRUE/FALSE 状态的位字段。

就像是:

+----+---------+
| ID | IsAlive |
+----+---------+
| 1  |    1    |
| 2  |    0    |
| 3  |   NULL  |
| 4  |    1    |
+----+---------+

使用该表作为我们的示例,我想创建一个存储过程,它将执行以下任一操作:

  1. 检索所有记录。
  2. 仅检索带有 的记录IsAlive=1
  3. 仅检索带有 的记录IsAlive=0 or NULL

我正在尝试考虑如何在无需编写 IF/ELSE 条件的情况下创建查询 - 在我看来,有一种比执行以下操作更好/更清洁的方法:

-- The ternary logic...
-- 0 or NULL retrieves records where IsAlive = 0 or NULL
-- 1 retrieves records where IsAlive = 1
-- Otherwise return all records 

-- sproc .....

    @IsAlive tinyint = 2 -- Return all records by default

    AS
    BEGIN
      IF(@SentToNTService = 0 OR @SentToNTService = 1)
       BEGIN
        SELECT *
        FROM MyTable
        WHERE IsAlive = @IsAlive;
       END
    ELSE -- Lame redundancy 
       BEGIN
        SELECT *
        FROM MyTable
       END  
    END

有没有另一种方法可以创建相同的结果而不必像我上面那样创建两个不同的查询?

4

5 回答 5

5

关于如何做到这一点的 2 条建议:

假设您的变量 @isalive 也被声明为“位”(应该是)

SELECT * FROM @t
WHERE @isalive is null or @isalive = coalesce(isalive, 0)

如果您想使用不需要 @isalive 为“位”的“位比较”解决方案(它适用于位和 tinyint)

SELECT * FROM @t
WHERE coalesce((1-coalesce(isalive, 0)) ^ @isalive, 1) > 0

第二种解决方案适用于像我这样的书呆子。一些铁杆人可能会觉得它很有趣(或者至少很有趣),因为我认为它提供了最好的性能(如果我错了,请有人纠正我)。这是一个强大的解决方案,但难以阅读。

于 2011-07-24T05:54:02.283 回答
3

这将做你想要的:

    SELECT *
    FROM MyTable
    WHERE COALESCE(IsAlive, 0) = COALESCE(@IsAlive, COALESCE(IsAlive, 0))

基于@IsAlive 的值:

  1. 如果为 NULL,则将返回所有内容(因为条件始终为真)
  2. 如果为 1,那么将返回 IsAlive = 1 的那些行
  3. 如果为 0,那么将返回 IsAlive = 0 或 NULL 的那些行

COALESCE 是一个返回它的第一个参数的函数,除非它是 NULL,在这种情况下它返回它的第二个参数。

因此,如果 IsAlive 为 NULL,则 LHS 返回 0;如果 IsAlive 为 1,则返回 0 和 1。当存储过程参数 @IsAlive 为 NULL 时,RHS 返回相同,否则仅返回 @IsAlive 参数。

编辑: 这假设@IsAlive 是位。在 tinyint 的情况下,您可以添加 case 语句:

    SELECT *
    FROM MyTable
    WHERE COALESCE(IsAlive, 0) = CASE @IsAlive
                                    WHEN 0 THEN 0
                                    WHEN 1 THEN 1
                                    ELSE COALESCE(IsAlive, 0)
                                 END
于 2011-07-23T23:30:32.923 回答
1

像这样的东西也应该起作用。

SELECT *        
FROM MyTable        
WHERE (@IsAlive = 0 and IsAlive=0)
OR (@IsAlive =1 and IsAlive =1)
OR (@IsAlive is null) 
于 2011-07-24T05:56:27.540 回答
1

尝试这个:

SELECT * FROM MyTable WHERE ISNULL (IsAlive, 0) = ISNULL (@IsAlive, 0)
UNION
SELECT * FROM MyTable WHERE ISNULL (@IsAlive, 0) > 1
于 2011-07-23T23:33:58.180 回答
1

这并不准确,但非常接近您可以执行的操作:

SELECT *        
FROM MyTable        
WHERE CASE @IsAlive
      WHEN 0 THEN IsAlive = @IsAlive
      WHEN 1 THEN IsAlive = @IsAlive
      ELSE 1=1 --dummy true value, when null or anything else
END
于 2011-07-23T23:34:56.797 回答