sql - 在tsql中使用 bool 代数来避免CASE语句或处理复杂的WHERE条件

标签 sql sql-server tsql case boolean-operations

我遇到了一个场景,我会用一些虚拟数据来解释它。见下表

Select * from LUEmployee

empId   name    joiningDate
1049    Jithin  3/9/2009
1017    Surya   1/2/2008
1089    Bineesh 8/24/2009
1090    Bless   7/15/2009
1014    Dennis  1/5/2008
1086    Sus     9/10/2009

只有当月份是一月、三月、七月或十二月时,我才需要将年份列增加 1。

empId   name    joiningDate derived Year
1049    Jithin  3/9/2009    2010
1017    Surya   1/2/2008    2009
1089    Bineesh 8/24/2009   2009
1090    Bless   7/15/2009   2010
1014    Dennis  1/5/2008    2009
1086    Sus     9/10/2009   2009

派生年份是必填列

我们可以通过下面的案例语句轻松实现这一点

Select *,
YEAR(joiningDate) + CASE WHEN MONTH(joiningDate) in (1,3,7,12) THEN 1 ELSE 0 END 
from LUEmployee

但是现场PM又来了一个条件,不要用CASE语句,CASE效率低。 在寻找解决方案的过程中,我们得出了以下解决方案,一种使用二进制 K-map 的解决方案,如下


如果数字1到12代表从Jan到Dec的月份,看二进制结果 enter image description here

下面给出卡诺图的表达方式。 enter image description here

结果会是

enter image description here

我们需要用sql server二元运算来实现表达式

eg: binary of 12 = 1100
    in the k-map, a = 1, b = 1, c = 0, d = 0
    Similarly, binary of 7 = 0111
    in the k-map, a = 0, b = 1, c = 1, d = 1

要获得最左边的位 (d),我们必须将位向右移动 3 个位置并屏蔽除 LSB 之外的所有位。

eg: ((MONTH(joiningDate)/8)&1)

类似地,左起第二位(c),我们需要将位向右移动2个位置,然后屏蔽除LSB之外的所有位

eg: ((MONTH(joiningDate)/4)&1)

最后,每个位可以表示为

so  a = ((MONTH(joiningDate)/8)&1)
    b = ((MONTH(joiningDate)/4)&1)
    c = ((MONTH(joiningDate)/2)&1)
    d = (MONTH(joiningDate)&1)

a inverse = (((MONTH(joiningDate)/8)&1)^1)
b inverse = (((MONTH(joiningDate)/4)&1)^1)
c inverse = (((MONTH(joiningDate)/2)&1)^1)
d inverse = ((MONTH(joiningDate)&1)^1)

最终代码将是

SELECT  *,
        YEAR(joiningDate) + CAST(
        ((MONTH(joiningDate)/8)&1)*((MONTH(joiningDate)/4)&1)*(((MONTH(joiningDate)/2)&1)^1)*((MONTH(joiningDate)&1)^1) |
        (((MONTH(joiningDate)/8)&1)^1)*(((MONTH(joiningDate)/4)&1)^1)*(MONTH(joiningDate)&1) |
        (((MONTH(joiningDate)/8)&1)^1)*((MONTH(joiningDate)/2)&1)*(MONTH(joiningDate)&1) 
        AS INT) [derivedYear]
FROM    LUEmployee

结果会是

enter image description here


问题: 可能有简单和不太复杂的想法,请分享。

我喜欢找一个更简单的,也喜欢分享想法。这里可能的条件是12(12个月)。我们可以使用 k-map 来处理更多的条件。感觉 k-map 最多可以处理 64 个条件。

最佳答案

我的第一 react 是捍卫在这种情况下使用 case 子句。但是如果您绝对不允许使用它,也许您可​​以简单地添加一个包含月份和增量值的表:

LUMonthIncrement

Month   Increment
 1      1  
 2      0  
 3      1  
 4      0  
 5      0  
 6      0  
 7      1  
 8      0  
 9      0  
10      0  
11      0  
12      1  

然后您可以加入该表并添加增量:

Select LUEmployee.*,
    YEAR(joiningDate) + LUMonthIncrement.Increment as derivedYear
from LUEmployee
    join LUMonthIncrement on MONTH(LUEmployee.joiningDate) = LUMonthIncrement.Month

虽然这不太可能更高效,因为为了加入 LUMonthIncrement,必须为LUEmployee 表。

关于sql - 在tsql中使用 bool 代数来避免CASE语句或处理复杂的WHERE条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23757036/

相关文章:

mysql - 不按 ID 排序时获取上一行 ID

sql - 检查 ROW 中的 EMAIL 格式并在 SELECT 查询中返回值

sql - SQL Server 2008 中列中出现的所有单词的字数统计

mysql - SELECT 复杂查询的相反行集

mysql - 如何使用sql查询将历史外汇数据从1分钟级别的数据聚合到10分钟级别的数据?

python - SQLAlchemy 错误 : "argument formats can' t be mixed"when inputting variables

sql-server - T-SQL Where 语句 - 或者

sql - SAS 将分钟添加到存储在宏变量中的时间戳

sql - 如何向使用 SELECT INTO 创建的表添加完整的主键

sql-server - 使用 tSQLt,如何在使用 GETUTCDATE() 时隔离对系统时钟的依赖?