2016-12-16 14 views
0

이 exemple이 같은 일의 목록을 작성하기 위해 오라클 계층 하위 쿼리를 사용하는 우리의 개발자와의 여기에 많은 이상한 물건 : 나를 위해오라클 내부 날짜 변환 : ORA-00932 및

WITH mydays AS (
    SELECT CAST(TO_DATE('20161201', 'YYYYMMDD') + ROWNUM AS DATE) AS d 
    FROM DUAL CONNECT BY TO_DATE('20161201', 'YYYYMMDD') + ROWNUM <= to_date('20161215', 'YYYYMMDD') 
) 

는 모습 CAST ... DATE을 DATE로 변환하기 때문에 DATE는 쓸모가 없어야합니다. 실제로는 그렇지 않습니다. 내가 만들고이 같은 테이블을 채우는 (나는 내 ​​데모에 가입해야합니다 ...) 경우 : CAST없이,

create table t(d date, i number); 
insert into t(d, i) values (to_date('20161204', 'YYYYMMDD'), 1); 
commit; 

을하고 그런 식으로 가입하여 쿼리를 시도, 나는이 계획을 설명 다음 얻을 :

WITH mydays AS (
    SELECT TO_DATE('20161201', 'YYYYMMDD') + ROWNUM AS d 
    FROM DUAL CONNECT BY TO_DATE('20161215', 'YYYYMMDD') + ROWNUM <= to_date('20161201', 'YYYYMMDD') 
) 
select mydays.d from mydays join t on t.d = mydays.d; 

. 캐스트와 함께

---------------------------------------------------------------------------------------- 
| Id | Operation      | Name | Rows | Bytes | Cost (%CPU)| Time  | 
---------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |  |  1 | 15 |  6 (17)| 00:00:01 | 
|* 1 | HASH JOIN      |  |  1 | 15 |  6 (17)| 00:00:01 | 
| 2 | VIEW       |  |  1 |  6 |  2 (0)| 00:00:01 | 
| 3 | COUNT      |  |  |  |   |   | 
|* 4 |  CONNECT BY WITHOUT FILTERING|  |  |  |   |   | 
| 5 |  FAST DUAL     |  |  1 |  |  2 (0)| 00:00:01 | 
| 6 | TABLE ACCESS FULL    | T |  1 |  9 |  3 (0)| 00:00:01 | 
---------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

1 - access("T"."D"=INTERNAL_FUNCTION("MYDAYS"."D")) 
4 - filter(TO_DATE(' 2016-12-15 00:00:00', 'syyyy-mm-dd 
      hh24:mi:ss')+ROWNUM<=TO_DATE(' 2016-12-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')) 

의 INTERNAL_FUNCTION는() 사라 :
4 - filter(TO_DATE(' 2016-12-01 00:00:00', 'syyyy-mm-dd 
      hh24:mi:ss')+ROWNUM<=TO_DATE(' 2016-12-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss')) 

내가 조금 인터넷 검색 및 변환이 ID (12)와 오라클 내부적으로 처리, 두 개의 내부 날짜 형식 사이 것을 발견 13, DUMP()에 대한 호출을 찾을 수 있습니다.

Typ=13 Len=8: 7,224,12,4,0,0,0,0 

캐스트와 함께 : 캐스트없이

Typ=12 Len=7: 120,116,12,4,1,1,1 

우리가하지 않고보다 CAST 덜 변환을해야한다고 설명한다 (!).

하지만 바인딩 변수를 넣으면 악화됩니다. 내가 얻고 싶은 경우,이 SQL의 계획을 설명 : ORA-00932 : 일관성없는 데이터 유형 : 예정일이 번호를 가지고

WITH mydays AS (
    SELECT TO_DATE(:beginning, 'YYYYMMDD') + ROWNUM AS d 
    FROM DUAL CONNECT BY TO_DATE(:end, 'YYYYMMDD') + ROWNUM <= to_date(:beginning, 'YYYYMMDD') 
) 
select mydays.d from mydays join t on t.d = mydays.d 

나는 오류가 발생합니다. CAST 마법을 추가하면 오류가 수정됩니다. 나는 계획을 생성 할 때 모든 바인드 변수가 VARCHAR2로 간주된다는 것을 알고 있습니다. 하지만 TO_DATE()에서는 DATE와 만 작업해야합니다. 맞습니까? 이 번호의 출처는 어디입니까?

내 뇌가 그 이상한 것들로 매우 지저분 해지기 시작하면 설명해 줄 수 있으면 고마워.

+0

CAST – Leo

+0

없이 오류없이 성공적으로 쿼리가 실행되었습니다. 사실 서브 쿼리의 종류를 사용하여보다 복잡한 쿼리를 작성하고 있으며 개발 중 100 %의 시간 동안 작동합니다. 생산의 시대. 오라클은이 쿼리에 대해 많은 설명 계획을 사용하고 있으며, 문제를 유발하는 계획은 하나 뿐이며 현재 어느 쿼리를 찾을 수 없습니다. –

+0

사용중인 Oracle 버전은 무엇입니까? 관찰 된 동작 ("외부"날짜 형식으로 문제가 발생하는 경우)은 특정 버전에 따라 매우 다를 수 있습니다. 'select * from v $ version'가 도움이 될 수 있습니다. – mathguy

답변

0

캘린더를받는 데 관심있는 검색어입니다. 읽기 쉬워 :

SELECT to_date('20160101','yyyymmdd') + LEVEL 
    FROM DUAL 
CONNECT BY LEVEL <= 90; 

당신은 해결책을 찾고 계시거나 지역의 문제점을 조사하고 계십니까?

+0

이 게시물은 무슨 일이 일어나는지 이해하는 것입니다. 하나 이상의 명시 적 또는 암시 적 변환 문제로 처리해야 할 더 복잡한 쿼리가 있으며 다른 쿼리를 놓치지 않도록 잘 이해해야하는 하위 쿼리가 있습니다. –

+0

@jeleb -이 솔루션에서'90'은 매직 넘버입니다. 물론 읽기가 쉽지만 개발자가 필요로하는 것이 아닙니다. 즉, LEVEL 또는 ROWNUM 중 어느 것을 사용하든 관계없이 CONNECT BY 조건은 왼쪽에 LEVEL 또는 ROWNUM이 있어야하고 to_date (. ..) ~ to_date (...)'를 선택하십시오. 이 방법은 계산이 "일정"(행마다 변경되지 않음)하므로 한 번 수행되어 반복적으로 사용됩니다. 그 결과보다 효율적인 질의가 가능합니다. – mathguy

+0

@jeleb : 그래서 테이블의 날짜 필드를 비교하여 select 문에 "Date + Number"구문을 암시 적으로 변환하는 것으로 추측합니다. 때로는 오라클이 이것이 (이 1 %에서) 숫자라고 판단합니다. Mayver 유용 할 수 있습니다. https://asktom.oracle.com/pls/apex/f?p=100:11:0::::p11_question_id:67082879150052 – Leo