2012-03-25 26 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