WHERE 子句中 CASE 中的布尔表达式不起作用

Boolean expression in CASE in WHERE clause does not work

我在使用 Firebird 2.5 版本的 SQL 语句时遇到问题。

根据今天的日期,我必须select本月的数据或上个月的数据。

SELECT * FROM FA_DOBAVNICA
WHERE
1=1

AND CASE WHEN
    extract(day from cast('Now' as date)) < 9
THEN
   DATUM_NAROCILA BETWEEN 'start of previous month' AND 'end of previous month'
ELSE
   DATUM_NAROCILA BETWEEN 'start of this month' AND 'end of this month'
END 

我收到 104 错误 Token unknown for BETWEEN。我不知道我做错了什么。

如果我正确理解了你的问题,你可以用这样的 or 子句重新措辞,它应该可以解决问题:

SELECT * FROM FA_DOBAVNICA
WHERE
1=1
AND 
((extract(day from cast('Now' as date)) < 9 AND DATUM_NAROCILA BETWEEN 'start of previous month' AND 'end of previous month')
or
(extract(day from cast('Now' as date)) > 8 AND DATUM_NAROCILA BETWEEN 'start of this month' AND 'end of this month'))

就我个人而言,我会避免在 where 中分叉条件变体,而是将其设为两个查询。我怀疑条件 where 可能会抑制 Firebird 的查询优化器,并且连接在一起的两个不同查询可能最终会得到一个更好的 查询计划 使用索引。

特别是如果您有比 1=1 占位符暗示的实际显示更多的条件。您必须使用真实数据和真实附加条件来检查和比较真实计划。

SELECT * FROM FA_DOBAVNICA 
WHERE extract(day from cast('Now' as date)) < 9
  AND DATUM_NAROCILA BETWEEN 'start of previous month' AND 'end of previous'

UNION ALL

SELECT * FROM FA_DOBAVNICA 
WHERE extract(day from cast('Now' as date)) >= 9 
  AND DATUM_NAROCILA BETWEEN 'start of this month' AND 'end of this month'

但是在您的具体情况下 - 为什么要使用 CASE?为什么不计算目标日期跨度呢?

WITH 
 TargetDay as 
   (SELECT DATEADD( -8 DAY TO CURRENT_DATE) AS TPoint FROM RDB$DATABASE)
,TargetStart as
   (SELECT DATEADD( 1 - EXTRACT(DAY FROM TPoint) DAY TO TPoint) AS TStart FROM TargetDay)
,TargetEnd as
   (SELECT DATEADD( -1 DAY TO DATEADD( 1 MONTH TO TStart)) AS TEnd FROM TargetStart)
   
select TStart, TEnd, TPoint from TargetStart, TargetEnd, TargetDay
TSTART TEND TPOINT
2021-08-01 2021-08-31 2021-08-03

db<>fiddle here

看到了吗?你根本不需要任何 if-then-else!

额外的好处是,您现在可以轻松地将 9 转换为 SQL 参数,而不是通过始终 [=22= 将其作为文字常量注入到 SQL 代码中],因为现在您只在查询中使用 9 一次,因此您不必再担心在始终同步的查询中更改两个不同的 parameters/constants。

WITH 
 TargetDay as 
   (SELECT DATEADD( 1 - (cast( ? as integer )) DAY TO CURRENT_DATE) AS TPoint FROM RDB$DATABASE)
,TargetStart as....

或者在像Delphi这样的语言中模拟Firebird的命名参数,它可以像

WITH 
 TargetDay as 
   (SELECT DATEADD( 1 - (cast( :ThresholdDay as integer )) DAY TO CURRENT_DATE) AS TPoint FROM RDB$DATABASE)
,TargetStart as....