如何在 T-SQL 中的位字段上创建三元条件

发布于 2024-11-26 02:26:00 字数 1023 浏览 3 评论 0原文

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

类似于:

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

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

  1. 检索所有记录。
  2. 仅检索带有 IsAlive=1 的记录。
  3. 仅检索 IsAlive=0 或 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

是否有另一种方法可以创建相同的结果而无需编写像我上面那样创建两个不同的查询?

I have a SQLExpress table that includes a bit field for storing TRUE/FALSE state.

Something like:

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

Using that table as our example, I want to create one Stored Procedure that will do any one of the following:

  1. Retrieve all records.
  2. Retrieve only the records with IsAlive=1.
  3. Retrieve only the records with IsAlive=0 or NULL.

I am trying to think of how I can create my query without having to write IF/ELSE conditions - It seems to me there is a better/cleaner way than to do something like this:

-- 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

Is there another way of creating the same results without having to create two different queries as I did above?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

弄潮 2024-12-03 02:26:00

关于如何执行此操作的 2 个建议:

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

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

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

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

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

2 suggestions of how to do this:

Assuming your variable @isalive is declared as 'bit' as well (which is should be)

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

If you want to use a 'bit compare' solution that doesn't require @isalive to be 'bit' (it will work for bit as well as tinyint)

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

Second solution is for nerds like me. Some hardcore people may find it interesting (or at least amusing) as I think it offer the best possible performance (please, someone correct me if i am wrong). It is a powerful solution but hard to read.

抚笙 2024-12-03 02:26:00

这将执行您想要的操作:

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

基于 @IsAlive 的值:

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

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

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

编辑:
这假设 @IsAlive 是 BIT。对于tinyint,你可以添加一个case语句:

    SELECT *
    FROM MyTable
    WHERE COALESCE(IsAlive, 0) = CASE @IsAlive
                                    WHEN 0 THEN 0
                                    WHEN 1 THEN 1
                                    ELSE COALESCE(IsAlive, 0)
                                 END

This will do what you want:

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

Based on the value of @IsAlive:

  1. If NULL, then will return everything (because the condition is always true)
  2. If 1, then will return those rows with IsAlive = 1
  3. If 0, then will return those rows with IsAlive = 0 or NULL

COALESCE is a function that returns it's first argument, unless it's NULL, in which case it returns its second argument.

So the LHS returns 0 if IsAlive is NULL or 0 and 1 if IsAlive is 1.
The RHS returns the same when the stored procedure argument @IsAlive is NULL and just returns the @IsAlive argument otherwise.

EDIT:
This assumed that @IsAlive is BIT. In the case of tinyint you can add a case statement:

    SELECT *
    FROM MyTable
    WHERE COALESCE(IsAlive, 0) = CASE @IsAlive
                                    WHEN 0 THEN 0
                                    WHEN 1 THEN 1
                                    ELSE COALESCE(IsAlive, 0)
                                 END
Bonjour°[大白 2024-12-03 02:26:00

试试这个:

SELECT * FROM MyTable WHERE ISNULL (IsAlive, 0) = ISNULL (@IsAlive, 0)
UNION
SELECT * FROM MyTable WHERE ISNULL (@IsAlive, 0) > 1

try this:

SELECT * FROM MyTable WHERE ISNULL (IsAlive, 0) = ISNULL (@IsAlive, 0)
UNION
SELECT * FROM MyTable WHERE ISNULL (@IsAlive, 0) > 1
亢潮 2024-12-03 02:26:00

这并不准确,但非常接近您可以做的事情:

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

This isnt exact, but pretty close to what you can do:

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
清晰传感 2024-12-03 02:26:00

像这样的东西也应该有效。

SELECT *        
FROM MyTable        
WHERE (@IsAlive = 0 and IsAlive=0)
OR (@IsAlive =1 and IsAlive =1)
OR (@IsAlive is null) 

Something like this should also work.

SELECT *        
FROM MyTable        
WHERE (@IsAlive = 0 and IsAlive=0)
OR (@IsAlive =1 and IsAlive =1)
OR (@IsAlive is null) 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文