2012-03-25 27 views
4

两个月之间进行选择生日这里没有fromdate和todate是在一份声明中我想是这样的一些参数:选择员工,在给定范围内的生日使用Oracle SQL

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

最后我们挑垃圾不同的解决方案,我们添加拳头创建周年日期:

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) 
1

,你应该能够使用

SELECT * FROM mytbale 
where dateofbirth between start_dt and end_dt 

备用:

您可以使用日期转换为一年中的一天:

to_char(thedate, 'ddd') 

然后检查范围(注意,这有与@Dems相同的问题在12月25日到1月10日期间不应该跨越年底。)

+1

-1:对不起,没有。这错过了OP的观点。 OP在5月5日至9月9日期间希望实施DoB,但不管年份如何。 – MatBailie 2012-03-25 16:11:39

+0

这是生日不诞生日期:) – 2012-03-25 16:16:48

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) 
     ) 
) 
+0

更改模式并不是一个真正的选择,但你的第二个解决方案可能没问题。我写了几个解决方案,但他们没有涵盖所有的情况... 我现在试试吧 – 2012-03-25 16:20:19

0

我不知道这是如何表现在性能方面,但我会尝试使用正则日期扣除。比如说,你想要在1月1日到7月1日之间的出生日。 25至25.5岁之间的任何人都有资格参加。也就是说,任何年龄不到半年的人都有资格参加。数学很容易达到1/2,但无论窗口如何,它都是一样的。换句话说,“一个月内”是指一年内+/- 1/12,一天内是指一年内+/- 1/365,依此类推。

年份在这个方法中并不重要,所以我将在创建变量时使用当年。另外,我会想到范围的中心,然后做绝对值(或者说,或者总是使用未来日期)。

例如

select personid 
from mytable 
where abs(mod(dob - target_birth_date)) < 1/52 

会给你每个人在一周内一个生日。

我意识到这个代码几乎没有伪代码,但似乎它可以让你做到这一点,你可能仍然使用索引,如果你调整了一点。只是想在箱子外面思考。

+0

这并不回答实际问题。你的查询对于(比方说)在接下来的两周内识别每个将要成为十八岁的人是有用的。但是,OP的问题是要求我们在接下来的两周内确定每个有生日的人,而不管他们会多大年纪*。 – APC 2012-04-16 11:58:33

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中,具有索引(基本上是相同的事物)的虚拟列 - 是索引日期列部分的唯一方法。

+0

我正在研究类似的案例。我不喜欢'to_char'谓词,以便利用索引。无论如何,除了创建基于函数的索引之外,还有什么可去的? – 2012-04-16 10:03:58

+0

谢谢APC,供您参考。 – 2012-04-17 09:17:08

-2

家伙,我有一个简单的解决这个问题

  • 步骤1转换到一个月
  • 第2步。将日期(两位数)连接到月份
  • 步骤3.然后通过执行to_number(结果)将结果转换为数字
  • 第4步。一旦你有这个开始日期和结束日期,然后做它之间的函数和你完成。

示例代码:

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))); 
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 
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, etc
  • 申请ceil()会给我们几年之间的差异,我们需要确定这个人是否有出生日期。例如。

    1. 年龄:29.9
    2. 29.9 +(20日)= 30.2
    3. 小区(30.1) - 小区(29.9)=

这是的结果查询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