【问题标题】:t-sql: Flipping a BETWEEN operator depending on row valuet-sql:根据行值翻转 BETWEEN 运算符
【发布时间】:2011-08-20 00:02:55
【问题描述】:

我在这里大大简化了我的示例,所以如果它看起来对我要解决的问题来说很简单,请原谅。

是否可以根据行值将BETWEEN 转换为NOT BETWEEN(为简单起见,我在这里使用了一个变量),而无需重复 between 语句?

我了解使用 case 语句和布尔逻辑来帮助使静态 sql 更加“动态”,但我似乎无法为像 BETWEEN 这样的运算符找到一种方法。

也许使用一些巧妙的按位运算?

我有一些基于集合的 SQL 在开发中已经变得难以管理,所以我希望通过避免重复来简化它。

我正在尝试以基于 SET 的方式进行操作,尽可能避免使用 UDF。

DECLARE @is int
set @is = 1

DECLARE @TestTable TABLE
(
    Name varchar(100),
    DOB datetime
)

INSERT INTO @TestTable(Name, DOB)
SELECT 'bob', '2011-08-18 10:10:10.100' UNION ALL
SELECT 'fred', '2014-08-18 10:10:10.100'


SELECT Name, DOB
FROM @TestTable
WHERE
    (@is = 1) AND (DOB BETWEEN '2011-08-18' AND '2012-08-18') 
    OR
    (@is = 0) AND (DOB NOT BETWEEN '2011-08-18' AND '2012-08-18')

所以在上面的例子中,如果@is = 1,则返回 bob。 如果@is = 0,则返回 fred。


编辑: 澄清一下,上述语句工作正常,但我正在尝试对其进行优化以避免编写 2 个 BETWEEN 语句。我希望根据 @is.... 的值翻转逻辑。在某处使用 is 放入 NOT。


编辑2:

请参阅下面的一些伪代码,了解我想要实现的目标。这是伪的,因为 t-SQL 不允许在这样的基于集合的操作中在代码中“注入”“NOT”(我试图避免字符串动态 sql)。

SELECT Name, DOB
FROM @TestTable
WHERE
(
    DOB
        CASE @is
            WHEN 0
            THEN NOT ---pseudo code, this won't actually work, but gives an idea of what I'm trying to achieve.
        END
    BETWEEN '2011-08-18' AND '2012-08-18'
) 

【问题讨论】:

    标签: sql tsql between


    【解决方案1】:

    我认为你只是需要更多的括号...

    WHERE
        (   (@is = 1) AND (DOB BETWEEN '2011-08-18' AND '2012-08-18')   )
        OR
        (   (@is = 0) AND (DOB NOT BETWEEN '2011-08-18' AND '2012-08-18')   )
    

    编辑

    知道了——然后是这样的:

    WHERE @is = CASE WHEN DOB BETWEEN '2011-08-18' AND '2012-08-18' THEN 1 ELSE 0 END
    

    【讨论】:

    • 对不起,库鲁,我认为我的问题不是很清楚。我的问题中的 SQL 工作正常。但我正在尝试对其进行优化,以避免需要编写 2 个 BETWEEN 语句,而是希望 BETWEEN 根据 @is 的值自动翻转到 NOT BETWEEN
    • 老兄!那是一些热门的 sql,来自我的 +1!非常优雅的解决方案。我只是从一个稍微不同的角度阅读了一个类似的答案,并试图理解它。您的修改来得正是时候,并且很好地解释了它。 stackoverflow.com/questions/1896828/… 会不会有我需要将其转换为一点的情况,或者它应该总是为我处理它?
    • 很高兴有帮助。 :-) 至于位转换,它只取决于你的变量。由于@is 是一个整数,它可以与 1 和 0 一起使用,就像它有点一样。但是,如果 @is 的值不是 1 和 0(例如“是”或“否”),那么您只需在 CASE 语句中将这些值替换为 1 和 0。跨度>
    • 感谢您提供的信息,事实上,我@is 的一个错字是有点意思。但听起来我不需要类型转换,很好的答案,谢谢。
    • 这个解决方案是完全不可分割的(不能使用索引)
    【解决方案2】:

    希望这会有所帮助。

        SELECT Name, DOB FROM @TestTable WHERE 
    CASE WHEN @is = 1 THEN DOB ELSE '1900' END BETWEEN '2011-08-18' AND '2012-08-18'
    

    【讨论】:

    • 有趣,谢谢 teenboy。 kuru 提供了一个很好的解决方案。但是感谢您的努力,您的看起来不错,我无法让它工作,但我喜欢语法的想法。来自我的 +1。
    【解决方案3】:

    只需使用逻辑将它们组合成一个语句:

    (@is = 1) = (DOB BETWEEN '2011-08-18' AND '2012-08-18') 
    

    这表示双方的“真相”必须相同(要么都为假,要么都为真),这就是你的代码可以简化为的。

    【讨论】:

    • TSQL 不允许您比较布尔语句的结果。您会认为它会起作用,但令人惊讶的是这无效......
    • 有趣的建议波西米亚谢谢。但是,我也试图返回相反的结果。所以如果@is = 0 仍然返回一个结果。我什至不确定我正在尝试做的事情是否可以在 sql 中表示:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 2020-10-03
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多