为了选择两个月之间的生日,其中FROMDATE和TODATE是预备语句中的一些参数,我想像这样:
select
p.id as person_id,
...
...
where e.active = 1
and extract(month from TODATE) >= extract(month from e.dateOfBirth)
and extract(month from e.dateOfBirth) >= extract(month from FROMDATE)
order by extract(month from e.dateOfBirth) DESC,
extract(day from e.dateOfBirth) DESC
如何改善这项工作以适应日子?
答案 0 :(得分:2)
在Oracle中搜索日期范围的方法不止一种。对于您的场景,我建议您将所涉及的所有日期的月和日元素转换为数字。
select
p.id as person_id,
...
...
where e.active = 1
and to_number (to_char( e.dateOfBirth, 'MMDD'))
between to_number (to_char( FROMDATE, 'MMDD'))
and to_number (to_char( TODATE, 'MMDD'))
order by extract(month from e.dateOfBirth) DESC,
extract(day from e.dateOfBirth) DESC
这不会使用e.dateOfBirth
列上的任何索引。这是否重要取决于您想要运行查询的频率。
@AdeelAnsari评论:
“我不喜欢to_char谓词,以便利用 索引“
什么指数? dateOfBirth
上的正常索引不会有任何用处,因为索引条目将以year元素引导。因此,它无法帮助您找到12月23日任何出生的人的所有记录。
基于函数的索引 - 或者在11g中,带有索引的虚拟列(基本上是相同的东西) - 是索引日期列部分的唯一方法。
答案 1 :(得分:1)
你应该可以使用
SELECT * FROM mytbale
where dateofbirth between start_dt and end_dt
替代:
您可以使用以下日期将日期转换为日期:
to_char( thedate, 'ddd' )
然后检查范围(请注意,这与@Dems回答的问题相同,在12月25日到1月10日之间不应该跨越年底。)
答案 2 :(得分:1)
您是否需要最高性能,因此愿意更改架构?或者记录的数量如此之小,性能相对不重要,您希望查询能够按原样处理数据吗?
最简单,最快捷的方法是存储第二个生育数据字段,但是“没有”年份。我把引号括在'没有',因为日期实际上不能有一年。所以,相反,你只需将它建立在另一年。
根据我的经验,将每个DoB重新安排到2000年是一个不错的选择。因为它包括一个闰年,并且是一个很好的数字。每个DoB和FromDate以及ToDate都将在2000年开始工作......
WHERE
DoB2000 >= FromDate
AND DoB2000 <= ToDate
(这假设您还索引新字段以快速进行搜索,否则您仍然可以进行扫描,尽管它可能比以下替代方案更快。)
或者,您可以继续使用EXTRACT模式。但那会产生不幸的后果;它非常混乱,你永远不会得到索引搜索,你将永远得到一个索引扫描。这是因为搜索字段包含在函数调用中。
WHERE
( EXTRACT(month FROM e.DateOfBirth) > EXTRACT(month FROM FromDate)
OR ( EXTRACT(month FROM e.DateOfBirth) = EXTRACT(month FROM FromDate)
AND EXTRACT(day FROM e.DateOfBirth) >= EXTRACT(day FROM FromDate)
)
)
AND
( EXTRACT(month FROM e.DateOfBirth) < EXTRACT(month FROM ToDate)
OR ( EXTRACT(month FROM e.DateOfBirth) = EXTRACT(month FROM ToDate)
AND EXTRACT(day FROM e.DateOfBirth) <= EXTRACT(day FROM ToDate)
)
)
答案 3 :(得分:1)
这是我在接下来的20天内用于birtdates的查询:
SELECT A.BIRTHDATE,
CEIL(ABS (MONTHS_BETWEEN(A.BIRTHDATE, SYSDATE) / 12)) AGE_NOW,
CEIL(ABS (MONTHS_BETWEEN(A.BIRTHDATE, SYSDATE + 20) / 12)) AGE_IN_20_DAYS
FROM USERS A
WHERE
CEIL(ABS (MONTHS_BETWEEN(A.BIRTHDATE, SYSDATE) / 12)) <> CEIL(ABS (MONTHS_BETWEEN(A.BIRTHDATE, SYSDATE + 20) / 12));
ABS (MONTHS_BETWEEN(A.BIRTHDATE, SYSDATE) / 12))
以38.9,27.2等格式返回年龄应用ceil()
会给我们多年的差异,我们需要确定这个人是否接近生日。例如
这是查询december 16
:
BIRTHDATE AGE_NOW AGE_IN_20_DAYS
12/29/1981 35 36
12/29/1967 49 50
1/3/1973 44 45
1/4/1968 49 50
答案 4 :(得分:0)
我不知道这在性能方面表现如何,但我会尝试使用常规日期减法。比如说,您想要1月1日到7月1日之间的分娩日。 25到25.5之间的任何人都有资格。也就是说,任何部分年龄不到1/2岁的人都符合资格。数学很容易在1/2,但无论窗口如何都是一样的。换句话说,“一个月内”意味着一年的+/- 1/12,一天内意味着一年+/- 1/365,依此类推。
年份与此方法无关,因此我将在创建变量时使用当前年份。
另外,我会想到范围的中心,然后做绝对值(要么是,要么总是使用未来的日期)。
例如
select personid
from mytable
where abs(mod(dob - target_birth_date)) < 1/52
会在一周内给大家一个生日。
我意识到这段代码几乎不是伪代码,但似乎它可能允许你这样做,如果你稍微调整它,你仍然可以使用索引。只是试着跳出框框思考。
答案 5 :(得分:0)
最后,我们选择了不同的解决方案,我们添加拳头创建周年纪念日期:
where
...
and (to_char(sysdate,'yyyy') - to_char(e.dateofbirth,'yyyy')) > 0
and add_months(e.dateofbirth,
(to_char(sysdate,'yyyy') - to_char(e.dateofbirth,'yyyy')) * 12)
>:fromDate:
and :toDate: > add_months(e.dateofbirth,
(to_char(sysdate,'yyyy') - to_char(e.dateofbirth,'yyyy')) * 12)
order by extract(month from e.dateofbirth) DESC,
extract(day from e.dateofbirth) DESC)
答案 6 :(得分:0)
这就是解决方案!!!
SELECT
*
FROM
PROFILE prof
where
to_date(to_char(prof.BIRTHDATE, 'DDMM'), 'DDMM') BETWEEN sysdate AND sysdate+5
或
add_months(to_date(to_char(prof.BIRTHDATE, 'DDMM'), 'DDMM'),12) BETWEEN sysdate AND sysdate+5
答案 7 :(得分:-2)
伙计我有一个更简单的解决方案来解决这个问题
示例代码:
SELECT date_of_birth
FROM xxxtable
where to_number(to_number(to_char(to_date(substr(date_of_birth,4,3),'mon'),'mm'))||substr(date_of_birth,1,2)) between
to_number(to_number(to_char(to_date(substr(:start_date_variable,4,3),'mon'),'mm'))||(substr(:start_date_variable,1,2))) and
to_number(to_number(to_char(to_date(substr(:end_date_variable,4,3),'mon'),'mm'))||(substr(:end_date_variable,1,2)));