2009-08-11 5 views
0

테이블 t1을 상상해 2 COLS 있습니다"스마트"여기서 필터링 값에 대한 절 (오라클 10g)

나는 2 PARAMS에 의해 하나의 행 찾으려
col1  col2 
-------------- 
test 900  1 
test 901  2 
test 902  3 
user 901  4 
test 909  5 

(이름, 코드)의 (테스트 이름, 사용자 등) 및 코드 - (901, 902, null, .. 등). 동일한 행 (코드, 이름)이 둘 이상일 수는 없습니다. Col1에 "test 901"이있는 행이 2 개가 없습니다.

코드 :

declare 
name varchar2(30); 
code varchar(10); 
col_val varchar2(30); 
col2_val numeric; 
begin 
name:= 'test'; 
code := '900'; 

    select col1, col2 into col_val, col2_val 
    from t1 
    where 

    (REGEXP_LIKE(col1, name||'\s+'||code) -- (3) 
    or (
     not REGEXP_LIKE(col1, name||'\s+'||code) -- (1) 
     and REGEXP_LIKE(col1, name) -- (2) 
    ) 
    ) 
    order by col1; 
    DBMS_OUTPUT.PUT_LINE('val:'||col_val||' id:'||col2_val); 
end; 

1) 테스트 값 이름 : = '테스트'코드 = '900'결과가 있어야한다 "발 : 시험 900 ID : 1"- 그것은 OK입니다.

2)하지만 이름 : = '테스트'코드 :하지만 내가 가진 "발 : 시험 900 ID : 1"= '909' 결과는 ": 시험 909 ID 5 발"이어야합니다 (Name = 'Test'가있는 첫 번째 행) - 원하는 것은 아닙니다. '999' 결과는 "val : test 900 id : 1"이어야합니다 (999 코드가 없으므로 해당 행이 필요합니다. 'Name'= 'test'내부에 있음).

주된 질문은 2) 예를 들어 WHERE oracle Ignores (1) 절입니까? 아마 내가 뭔가 잘못하고있는 것 같습니다. 실수를해도 좋을 것 같습니다.

+0

where 절에서 "rownum = 1"행을 제거했습니다. Tnks Thilo. – zmische

답변

0

이 조건 :

(REGEXP_LIKE(col1, :name || '\s+' || :code) 
OR (NOT REGEXP_LIKE(col1, :name || '\s+' || :code) AND REGEXP_LIKE(col1, :name)) 

이 예에서 모든 행을 일치합니다.

test 909을 검색 할 때 'test 909' OR (NOT 'test 909' AND 'test')을 찾습니다. 이 값은 'test'부터 시작하는 모든 행과 일치합니다 (첫 번째 조건 또는 초당).

당신이 rownum = 1을 사용하고 있기 때문에, (모든 'test' 그렇지 않으면이 존재하는 경우 'test 909' 반환)이 사용 당신은 대체 일치 원하는 경우 귀하의 경우 'test 900'

에 반환에 일치하는 첫 번째 열 :

SELECT * 
FROM (
     SELECT * 
     FROM t1 
     WHERE REGEXP_LIKE(col1, name || '\s+' || code) 
     UNION ALL 
     SELECT * 
     FROM t1 
     WHERE REGEXP_LIKE(col1, name) 
     ) 
WHERE rownum = 1 

, 또는 당신이 UNION의 마음에 들지 않는 경우 :

SELECT * 
FROM (
     SELECT * 
     FROM t1 
     WHERE REGEXP_LIKE(col1, name) 
     ORDER BY 
       CASE WHEN REGEXP_LIKE(col1, name || '\s+' || code) THEN 0 ELSE 1 END 
     ) 
WHERE rownum = 1 

을 후자의 경우에는 정렬해야하기 때문에 효율성이 떨어집니다.

+0

rownum = 1 실수로 거기에있었습니다. 나는 그것을 제거했다. 문제는 2) 예제에서는 단 하나의 행만 얻을 수 없다는 것입니다! 나는이 같은 조항을 가지고 가능한 경우 donno. – zmische

+0

예! 너는 나에게 맞다. 나는 fallbak match를 원한다. 하지만 이것은 UNION없이 가능합니까 ??? 노동 조합에 대해서는 생각했지만이 해결책과 같은 것이 었습니다. – zmische

+0

'@ zmische' :'UNION'에는 아무 것도 없습니다. 나는 분명히 당신에게'UNION '이없는 해결책을 줄 수는 있지만, 덜 효과적 일 것입니다. – Quassnoi

0

ROWNUM은 행 번호 이므로이 정렬되기 전에 ROWNUM과 ORDER BY를 결합 할 수 없습니다.

당신은 더 자세한 얻을

select a.* from (
    select * from table order by col1) a 
    where rownum = 1; 

확인처럼 ROWNUM 및 페이징에 대한 문서를 뭔가를 작성해야합니다.

+0

Thilo, 고마워요. 제 코드에서 복사했습니다. 그러나 문제는 여전히 존재합니다 - rownum = 1이 없으면 2) 예제에서 필요한 결과를 얻을 수 없습니다 !!! – zmische

0

col1의 부분을 별도의 열에 저장하는 것이 훨씬 나을 것입니다. 어쨌든, Thilo가 말한 것 외에 한 가지 더 있습니다.

ROWNUM 부분을 무시하고, 테이블의 네 개의 행은 예에서 WHERE 절을 일치합니다. 영어의 WHERE 절은 "이름과 코드가 모두 일치하거나 다른 경우 모두 일치하지 않지만 이름이 일치합니다."

이 말의 복잡한 방법입니다 "이름과 일치"및 절은 그 정말 만약 당신이 무엇을 의미하는지 등의 복잡한 필요가 없습니다.

(\ s는 잘 모르는 공백을 의미합니다. 이름이 일치하고 이름 뒤에 공백이 있습니다.) 이름 만 일치하는 항목 앞에 "모두"일치하는 것을 보려면 이 "득점"위해 첫 번째 행을 선택합니다

ORDER BY 
    CASE WHEN REGEXP_LIKE(col1, name||'\s+'||code) THEN 2 
     WHEN REGEXP_LIKE(col1, name||'\s+) THEN 1 
    ELSE 0 END DESC 

응답 코멘트 :

귀하의 절은 을 표현하는 데 실패하지만 WHERE하지 않을 경우, ... 당신의 필요 조건의 측면. 이 코드 및 이름이나 단지 그것을를 보여, 그것의 이름으로 행 모두 행이며, 그것은 당신의 필요 조건이 아닌 경우 귀하의 WHERE 절은 단순히 을 표현한다. 아니, 다음을 B 경우 을 표현하는

는 WHERE A,하지만, 당신이

WHERE <condition A> OR (NOT <condition A> AND <condition B>) 

를 작성하거나 내가했던 것처럼 뭔가를해야

WHERE <condition A> OR <condition B> 

를 작성하는 작동하지 않습니다 내 CASE 표현식으로

도움이 되었습니까?

+0

랭킹은 OK입니다. 단지 where 절에서 어디에서 실수했는지 알고 싶었습니다. "where 절"을 통해 필요한 행을 얻을 수있었습니다. 내 where 절이 "name matches"와 똑같다는 것에 동의하지 않습니다. "- 그, 을 보여하지만 아무도이없는 경우 - 행 코드와 이름 모두가 있으면 그냥에서 이름 행 찾을 시도" 가 : 나는이 같은 읽혀질해야한다 생각했다. – zmische

+0

@zmishce : 내 대답에 내가 무엇을 추가했는지 확인하십시오. –