如何在 Oracle SQL 的 Where 语句中添加大小写
Posted
技术标签:
【中文标题】如何在 Oracle SQL 的 Where 语句中添加大小写【英文标题】:How to put Case in Where Statement for Oracle SQL 【发布时间】:2020-02-24 14:44:05 【问题描述】:对于下面的查询,我试图根据当月的当天提取特定的日期范围。如果是 20 日或更少(例如“2/7/2020”),那么我想要 1 月的日期范围。否则,我想要二月的日期范围。是否可以通过案例陈述来完成?还是有更好的办法?
SELECT
account,
start_date,
amount
FROM
table1
WHERE
CASE
WHEN (
SELECT
CAST(EXTRACT(DAY FROM sysdate) AS NUMBER)
FROM
dual
) <= 20 THEN
start_date
BETWEEN '2020-01-01' AND '2020-01-31'
ELSE start_date BETWEEN '2020-02-01' AND '2020-02-29'
END
【问题讨论】:
附带说明:(SELECT CAST(EXTRACT(DAY FROM sysdate) AS NUMBER) FROM dual)
只不过是EXTRACT(DAY FROM sysdate)
。 start_date BETWEEN '2020-01-01' AND '2020-01-31'
应该是 start_date BETWEEN DATE '2020-01-01' AND DATE '2020-01-31'
。结果是一个布尔值,如果 Oracle 在 SQL 中提供 BOOLEAN
,这将起作用,不幸的是它没有。
【参考方案1】:
您可以通过避免使用 case 语句并使用截断日期 - 20 到月份来做到这一点,例如:
SELECT account,
start_date,
amount
FROM table1
WHERE start_date >= TRUNC(SYSDATE - 20, 'mm')
AND start_date < add_months(TRUNC(dt - 20, 'mm'), 1);
如果您真的必须使用 CASE
表达式(您不能在 SQL 中使用 CASE
语句),您需要执行以下操作:
SELECT account,
start_date,
amount
FROM table1
WHERE start_date >= CASE WHEN to_char(SYSDATE, 'dd') <= '20' THEN add_months(TRUNC(SYSDATE, 'mm'), -1) ELSE TRUNC(SYSDATE, 'mm') END
AND start_date < CASE WHEN to_char(SYSDATE, 'dd') <= '20' THEN TRUNC(SYSDATE, 'mm') ELSE add_months(TRUNC(SYSDATE, 'mm'), 1) END;
注意如果使用的是函数,则不需要将其包裹在select .. from dual
中,可以直接在SQL语句中使用。
我还假设您想要一个动态范围,例如如果该月的日期为 20 或更少,则范围为上个月,否则为当前月份。
ETA:如果start_date
列上有索引,您将使用上述两个查询,否则您可以简单地这样做:
SELECT account,
start_date,
amount
FROM table1
WHERE TRUNC(start_date, 'mm') = TRUNC(SYSDATE - 20, 'mm');
【讨论】:
to_char(SYSDATE, 'dy')
输出mon
(db<>fiddle);您可能希望 dd
作为格式模型(Oracle 将执行隐式字符串到数字的转换),或者像 OP 在他们的问题中那样使用 EXTRACT( DAY FROM SYSDATE)
。【参考方案2】:
Case 语句返回单个值。因此,您应该提取开始日期,并且需要两个案例陈述。
select account, start_date, amount
from table1 where
start_date between
(case
when (select cast(extract(day from sysdate) as number) from dual) <= 20 then '2020-01-01'
else '2020-02-01'
end) and
(case
when (select cast(extract(day from sysdate) as number) from dual) <= 20 then '2020-01-31'
else '2020-02-29'
end)
【讨论】:
您不需要(select cast( extract( day from sysdate ) as number ) from dual)
,您可以使用extract( day from sysdate )
。此外,'2020-01-01'
是字符串文字,不是日期; Oracle 将隐式尝试使用 NLS_DATE_FORMAT
会话参数将字符串转换为日期,但每个用户都可以在任何时候为此格式模型设置自己的值,因此您永远不应依赖默认格式并使用日期文字 (@987654326 @) 或 TO_DATE
函数使用显式格式模型。【参考方案3】:
一种方法减去 20 天,然后得到月份边界:
where start_date >= trunc(sysdate - interval '20' day, 'MON') and
start_date < trunc(sysdate - interval '20' day, 'MON') + interval '1' month
这种方法对索引(和分区)友好——可以使用start_date
上的适当索引。如果start_date
有时间分量也是安全的。
注意:您可以使用sysdate
而不必使用子查询。
【讨论】:
【参考方案4】:您可以将or
运算符与last_day
函数一起使用,如下所示:
Select * from your_table
Where (
start_date <= trunc(sysdate,'mm') + 20
and start_date between trunc(sysdate,'mm') - interval '1' month and trunc(sysdate,'mm') - 1
)
Or
(
start_date > trunc(sysdate,'mm') + 20
and start_date between trunc(sysdate, 'mm') and last_day(sysdate)
)
此方法将使用start_date
上的索引(如果有)。
干杯!!
【讨论】:
【参考方案5】: select account, amount, start_date
from table1
where ( ( (select cast (extract (day from sysdate) as number) from dual) <= 20
and start_date between date '2020-01-01' and date '2020-01-31')
or ( (select cast (extract (day from sysdate) as number) from dual) > 20
and start_date between date '2020-02-01' and date '2020-02-29')
);
【讨论】:
【参考方案6】:使用 CASE 表达式作为 BETWEEN 操作数:
SELECT account
, start_date
, amount
FROM table1
WHERE start_date BETWEEN CASE
WHEN extract(day from sysdate) <= 20
THEN trunc(sysdate -interval '1' month, 'month')
ELSE trunc(sysdate, 'month')
END
AND CASE
WHEN extract(day from sysdate) <= 20
THEN last_day(sysdate -interval '1' month)
ELSE last_day(sysdate)
END
【讨论】:
以上是关于如何在 Oracle SQL 的 Where 语句中添加大小写的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Oracle SQL 的 Where 语句中添加大小写
如何优化Oracle在where条件中用了自定义函数的SQL语句