[질문] 문자열 비교 방법 문의 0 13 5,964

by 손님 문자열비교 [2010.09.27 09:55:09]



주민번호 13자리중 11자리가 동일한 사람을 찾고 싶습니다.

찾고자 하는 기준은 어떤 대상자가 있고 그 대상자 중에서

주민번호의 11자리가 동일한 사람을 찾고하 하는 것입니다.

어떻게 찾아할지 방법을 좀 알려 주시면 감사하겠습니다.

예를 들어

551203-1234567
551203-1234568
551203-2456790
551103-1234567
571101-1234567

이런 데이터가 있을 때
551203-1234567 의 11자리 동일자는 551203-1234568, 551103-1234567 이고
551103-1234567 의 11자리 동일자는 571101-1234567 이겠지요..

이렇게 찾고자 하는 겁니다.
by 마농 [2010.09.27 11:06:17]
WITH t AS
(
SELECT '551203-1234567' jno FROM dual
UNION ALL SELECT '551203-1234568' FROM dual
UNION ALL SELECT '551203-2456790' FROM dual
UNION ALL SELECT '551103-1234567' FROM dual
UNION ALL SELECT '571101-1234567' FROM dual
)
SELECT jno
FROM t
, (SELECT level lv FROM dual CONNECT BY level <= 14)
WHERE SUBSTR(jno, lv, 1) = SUBSTR('551203-1234567', lv, 1)
GROUP BY jno
HAVING COUNT(*) > 11
;

by 손님 [2010.09.27 12:19:27]
감사합니다...

그런데 대상건이 4만건이지만 비교대상이 5천만건이 넘거든요..

혹시 속도는 빨리 할 수 있는 방법이 없을 까요...

by .. [2010.09.27 13:31:13]
마농님께서 어떤 기발한 아이디어를 내실지 궁금해지네요.

by 마농 [2010.09.27 13:34:05]
특정 주민번호 하나로 찾는것이 아니었나요?
4만건을 대상으로 5천만건에서 찾는다면?
단순 이퀄조건으로도 시간이 오래 걸릴듯 합니다.
이퀄조건이 아닌 애매한 조건으로는 답이 안나올것 같다고 조심스레 생각해 봅니다.
건수가 적다면 여러가지 방법을 생각해 보고 시도해 볼수도 있겠으나 제시하신 건수로는 힘들지 않을까요?......

by 손님 [2010.09.27 13:47:41]
대상 4만건을 한건씩 패치해서 처리해야 합니다..

by 병아리 [2010.09.27 14:02:29]
with t as(
SELECT '551203-1234567' jno FROM dual
UNION ALL SELECT '551203-1234568' FROM dual
UNION ALL SELECT '551203-2456790' FROM dual
UNION ALL SELECT '551103-1234567' FROM dual
UNION ALL SELECT '571101-1234567' FROM dual
UNION ALL SELECT '571101-1234568' FROM dual
)
select
min(jno) jno
from
(
select
jno,
dense_rank()over(order by substr(jno,1,13)) b
from t
)
group by b
having count(*) > 1

by 마농 [2010.09.27 14:28:35]
일단 5천만건을 풀스캔하면서 찾는것은 부담이 될듯 합니다.
주민번호에 인덱스가 있다고 가정하고
인덱스를 테우려면 이퀄이나 Like 검색을 해야 하는데
Like도 첫자리가 같다면 문제 없지만? 첫자리가 다른 경우엔 풀스캔을 타야 합니다.
그래서 생각해 본것이 특정 주민번호와 11자리 이상 동일한 주민번호를 모두 추정한다면 몇건이 될까?
이 주민번호들을 임의로 만들어 낸다면 이를 가지고 인덱스 스캔을 유도할 수 있지 않을까?
그래서 임의로 13자리중 임의의 두자리를 0~9까지 뺑뺑이 돌리면서 주민번호를 만들어 봤습니다.

SELECT DISTINCT
SUBSTR(jno, 1, v1-1) || v3 || SUBSTR(jno, v1+1, v2-v1-1) || v4 || SUBSTR(jno, v2+1) v
FROM (SELECT '551203-1234567' jno FROM dual)
, (SELECT level v1 FROM dual WHERE level <> 7 CONNECT BY level <= 14)
, (SELECT level v2 FROM dual WHERE level <> 7 CONNECT BY level <= 14)
, (SELECT level-1 v3 FROM dual CONNECT BY level <= 10)
, (SELECT level-1 v4 FROM dual CONNECT BY level <= 10)
WHERE v1 < v2
;

6436건이 나오네요.
음.. 꽤 큰 숫이긴 하지만 5천만건이라는 수에 비한다면 얼마 안될듯 하네요.
이 결과를 IN 조건으로 5천만건 자료에 제공해서 찾아보면
인덱스 유니크 스캔 6436번으로 결과를 얻을 수 있을듯 합니다.

일단 주민번호 한개로 처음 제시했던 쿼리와 시간 비교해 보세요.

by 마농 [2010.09.27 14:53:40]
주민번호 3번째 자리는 0과 1 두가지만 가능하고
주민번호 5번째 자리는 0~3 까지만 가능하므로
이를 제한조건으로 준다면? 건수를 더 줄일 수 있네요. 4958건

SELECT DISTINCT
SUBSTR(jno, 1, v1-1) || v3 || SUBSTR(jno, v1+1, v2-v1-1) || v4 || SUBSTR(jno, v2+1) v
FROM (SELECT '551203-1234567' jno FROM dual)
, (SELECT level v1 FROM dual WHERE level <> 7 CONNECT BY level <= 14)
, (SELECT level v2 FROM dual WHERE level <> 7 CONNECT BY level <= 14)
, (SELECT level-1 v3 FROM dual CONNECT BY level <= 10)
, (SELECT level-1 v4 FROM dual CONNECT BY level <= 10)
WHERE v1 < v2
AND v3 <= DECODE(v1, 3, 1, 5, 3, 9)
AND v4 <= DECODE(v2, 3, 1, 5, 3, 9)
;

by 마농 [2010.09.27 15:19:56]
-- 조금 더 걸러봤습니다. 3952건
SELECT v
FROM
(
SELECT DISTINCT
SUBSTR(jno, 1, v1-1) || v3 || SUBSTR(jno, v1+1, v2-v1-1) || v4 || SUBSTR(jno, v2+1) v
FROM (SELECT '551203-1234567' jno FROM dual)
, (SELECT level v1 FROM dual WHERE level <> 7 CONNECT BY level <= 14)
, (SELECT level v2 FROM dual WHERE level <> 7 CONNECT BY level <= 14)
, (SELECT level-1 v3 FROM dual CONNECT BY level <= 10)
, (SELECT level-1 v4 FROM dual CONNECT BY level <= 10)
WHERE v1 < v2
AND v3 <= DECODE(v1, 3, 1, 5, 3, 9)
AND v4 <= DECODE(v2, 3, 1, 5, 3, 9)
)
WHERE SUBSTR(v,3,2) BETWEEN '01' AND '12'
AND SUBSTR(v,5,2) BETWEEN '01' AND '31'
AND NOT(SUBSTR(v,1,2) > '10' AND SUBSTR(v,8,1) IN ('3','4'))
;

by .. [2010.09.27 15:28:00]
마농님은 어떻게 저런 발상을 하실까......
Oracle퀴즈(초급) 좀 운영해 주시면 안될까요....
실명을 걸고 도전해 보겠습니다

by finecomp [2010.09.27 20:36:27]
제가 봤을 땐, 둘 중 하나로 선택하실 수 있겠네요.

1. 질문자분의 cursor fetch를 최대한 반영하여 마농님이 마지막에 제시하신 의견처럼 4만 * 약4천건의 random access냐 (결국 access는 4천만 또는 그 이상일 듯...;)

2. 4만*14 built-in 집합과 5천만*14 probe 집합을 만들어 마농님이 처음 제시하신 의견을 이용하여 hash join하느냐
full scan시 parallel처리까지 가지 않더라도
ALTER SESSION SET db_file_multiblock_read_count = 128; 정도 설정만으로 full scan 성능이 꽤 향상됩니다.

by 손님 [2010.09.27 21:27:44]

답변 주신분들께 감사드립니다..

딴일 때문에 바뻐서 들어와 보질 못했네요..

꼭 첫째자리가 같다는 보장은 없습니다..

그리고 중간에 - 도 없습니다..

보기 편하게 할려고 넣었던 것인데.. 그만 일을 만들었군요..


추가 조건이 있습니다.

성별란 - 다음 첫자리가 1~4인 것만이 대상입니다.

5-8까지도 있는데 이경우는 외국인이기때문에 대상에서 제외하고 처리할 예정이거든요..

by 손님 [2010.09.28 14:11:16]
다시 한 번 답변주신 분들께 감사의 말씀을 드립니다..

처리를 해보니 아래와 같이 하는게 처리속도면에서 훨씬 빠르네요...

SELECT 주민번호
, 성명
FROM (
SELECT 주민번호
, 성명
, CASE WHEN SUBSTR(주민번호, 1, 1) = SUBSTR( :주민번호, 1, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 2, 1) = SUBSTR( :주민번호, 2, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 3, 1) = SUBSTR( :주민번호, 3, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 4, 1) = SUBSTR( :주민번호, 4, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 5, 1) = SUBSTR( :주민번호, 5, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 6, 1) = SUBSTR( :주민번호, 6, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 7, 1) = SUBSTR( :주민번호, 7, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 8, 1) = SUBSTR( :주민번호, 8, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 9, 1) = SUBSTR( :주민번호, 9, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 10, 1) = SUBSTR( :주민번호, 10, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 11, 1) = SUBSTR( :주민번호, 11, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 12, 1) = SUBSTR( :주민번호, 12, 1) THEN 1 ELSE 0 END
+ CASE WHEN SUBSTR(주민번호, 13, 1) = SUBSTR( :주민번호, 13, 1) THEN 1 ELSE 0 END 건수
FROM 테이블
WHERE 성명 LIKE :성명'||%'
AND 주민번호 <> :주민번호
AND SUBSTR(주민번호, 7, 1) IN ('1', '2', '3', '4')
)
WHERE 건수 >= 11
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입