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....
我在使用 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....