2017-03-06 75 views
0

問:我如何選擇甲骨文的兩個日期之間只有週五日期SQL查詢來獲取只有週五日兩個日期之間

SELECT dates,TO_CHAR(dates,'day-mon-yyyy') 
FROM 
(SELECT to_date('01-jan-12','dd-mon-yy')+rownum -1 AS dates 
    FROM addresses 
WHERE rownum <= to_date('31-jan-12','dd-mon-yy')- to_date('01-jan-12','dd-mon-yy')+1) 
WHERE upper(regexp_substr(TO_CHAR(dates,'day-mon-yy'),'([[:alpha:]])+'))=upper('FRIDAY'); 

我需要的輸出,如:

06-JAN-12 FRIDAY        
13-JAN-12 FRIDAY        
20-JAN-12 FRIDAY        
27-JAN-12 FRIDAY        
03-FEB-12 FRIDAY        
10-FEB-12 FRIDAY        
17-FEB-12 FRIDAY        
24-FEB-12 FRIDAY        
02-MAR-12 FRIDAY        
09-MAR-12 FRIDAY        
16-MAR-12 FRIDAY        
23-MAR-12 FRIDAY        
30-MAR-12 FRIDAY

訪問更多的SQL查詢:SQL Query Interview Questions

+1

請閱讀[問] – OldProgrammer

+0

什麼是您的問題/問題/錯誤?您所展示的內容在日期字符串周圍需要單引號,但是...無論如何,似乎相當複雜,地址表的相關內容是什麼? –

+0

非常感謝你,我現在忘了單引號,它工作正常 –

回答

1

由於您用作to_char()的第一個參數的值未包含在單引號中,因此會發布您發佈的錯誤:

select to_date(01-jan-12,'dd-mon-yy') from dual; 

ORA-00904: "JAN": invalid identifier 

因爲沒有報價,jan在您的地址表中解釋爲標識,並有(大概)沒有列呼叫JAN。使用2位數年份也是不好的做法,並且您必須(從真正的舊數據中)使用RR通常比YY更好。月份名稱也受NLS設置的影響,因此使用月份數字比名稱更安全;如果你真的想要名字to_char()函數有第三個參數來控制語言。

您正在以相當複雜的方式執行此操作,並且您依賴的地址表有足夠的行數。通過day而不是DAY指定您希望小寫字母的日期名稱,然後將其設爲大寫,然後剝離字符串的位 - 您首先指定的位! - 只獲取日期名稱,然後再比較假設(再次)NLS設置會爲您提供英文日期名稱......無謂地令人費解。正如您要求固定的字符串文字upper()所示,您可以(並且)以大寫形式提供。

而不是

WHERE upper(regexp_substr(TO_CHAR(dates,'day-mon-yy'),'([[:alpha:]])+'))=upper('FRIDAY'); 

,你可以做任何這些或其他變化:

WHERE regexp_substr(TO_CHAR(dates,'DAY-mon- 
y'),'([[:alpha:]])+')=upper('FRIDAY'); 
WHERE TO_CHAR(dates,'DAY')='FRIDAY '; 
WHERE TRIM(TO_CHAR(dates,'DAY'))=upper('FRIDAY'); 
WHERE TO_CHAR(dates,'FMDAY','NLS_DATE_LANGUAGE=ENGLISH')='FRIDAY'; 

您可避免通過使用分層查詢,對dual表依託地址表:

SELECT next_day(date '2012-01-01' - 1, 'FRIDAY') + (7 * (level - 1)) 
FROM dual 
CONNECT BY next_day(date '2012-01-01' - 1, 'FRIDAY') + (7 * (level - 1)) 
    <= date '2012-03-31'; 

使用next_day也依賴於關於NLS設置的,所以除非你能隨時控制會議日期的語言,它可能是安全的(如果有點低效率)來獲取所有的日期,然後在NLS-獨立的方式進行篩選:

SELECT dates, to_char(dates, 'FMDAY') 
FROM (
    SELECT date '2012-01-01' + level - 1 AS dates 
    FROM dual 
    CONNECT BY level <= date '2012-03-31' - date '2012-01-01' 
) 
WHERE to_char(dates, 'FMDAY', 'NLS_DATE_LANGUAGE=ENGLISH') = 'FRIDAY'; 

DATES  TO_CHAR(DATES,'FMDAY')    
--------- ------------------------------------ 
06-JAN-12 FRIDAY        
13-JAN-12 FRIDAY        
20-JAN-12 FRIDAY        
27-JAN-12 FRIDAY        
03-FEB-12 FRIDAY        
10-FEB-12 FRIDAY        
17-FEB-12 FRIDAY        
24-FEB-12 FRIDAY        
02-MAR-12 FRIDAY        
09-MAR-12 FRIDAY        
16-MAR-12 FRIDAY        
23-MAR-12 FRIDAY        
30-MAR-12 FRIDAY        

13 rows selected. 

作爲@mathguy在評論中指出,雖然next_day()是NLS敏感,你可以使用第二個參數的表達,所以不是硬編碼天名,你可以這樣做:

next_day(date '2012-01-01' - 1, to_char(date '1999-12-31', 'FMDAY')) 

,其中1999- 12-31可以是已知的任何星期五的日期;如果您不介意選擇列表中的表達式和連接條款不同(並且實際上,您 - 我也不應該!),則可以減少該檢查的計算成本:

SELECT dates, to_char(dates, 'FMDAY', 'NLS_DATE_LANGUAGE=ENGLISH') 
FROM (
    SELECT next_day(date '2012-01-01' - 1, 
    to_char(date '1999-12-31', 'FMDAY')) + (7 * (level - 1)) AS dates 
    FROM dual 
    CONNECT BY level <= 1 + (date '2012-03-31' - next_day(date '2012-01-01' - 1, 
    to_char(date '1999-12-31', 'FMDAY')))/7 
); 

無論會話的日期語言如何,它都獲得與上面相同的13行。如果您希望輸出也採用會話語言,只需刪除覆蓋的第三個參數to_char()

+1

使用'next_day()'的解決方案可能是最有效的。爲了使它獨立於調用會話的語言,我們可以計算'to_char(some_date,'Day')'爲'some_date',這個被稱爲星期五 - 然後在'next_day()'的調用中使用它。同樣的解決方案可以通過解決connect by中'level'的不平等問題(也就是把它寫成'level <= 1 +( - )/ 7'),這樣RHS是對於整個查詢只計算一次;在當前形式中,每行都有額外的算術計算 – mathguy

+0

@mathguy - 呵呵,出於某種原因,我認爲next_day()的第二個參數必須是文字而不是表達式;不知道從哪裏得到的,因爲它顯然是不正確的;同意將計算移動到RHS以提高效率;爲了可讀性,使用connect-by中的相同表達式作爲選擇列表可能會有幫助,但是是成本這裏的區別可能很重要,所以在這種情況下這不是一個令人信服的論點,謝謝。 –

相關問題