Shrink를 이용하기 전에, 검토해야 할것과 Shrink의 기능이 왜 생겨났는지를 알아야 한다.

우선, 여러분이 Delete 를 해서 Table에 수천만건이 있다가 1건으로 줄이더라도 실제 데이터를 검색하기 위해서는 이미 할당된 공간을 full scan하거나, High Warter Mark 까지 체크하는 것을 이해해야 한다.

그리고, Archive log에 변경이력이 쌓이는 걸 알아야 한다. Shrink는 데이터의 저장된 구조를 변경하는 것이다.
(블록에 적재된 데이터의 량이 들쑥날쑥하고, row-chaining 등이 많다면, 동일한 데이터라도 table을 읽을 때 시간이 많이 걸린다).

그래서 triger로 인한 추가적인 DB변경은 발생하지 않지만, 실제 row를 delete/insert 작업을 통해 재정렬하는 것이기에 Archive log 파일이 대량으로 생성될 수 있다. 그래서 데이터가 많은 테이블을 Shrink할 경우에는 Archive log 의 디렉토리를 확인하여 백업이 된 log 파일은 삭제할 것을 권고한다.

제일 좋은 것은, 운영 중, 불필요한 데이터를 이관하거나 삭제하는 것이다.
(개인정보보호법에 따라, 불필요한 정보는 즉시(5일이내) 삭제해야 하며, Log 테이블은 partition되어 있고, 매일 증가분에 대해 이관하였다면, drop partition을 통해 정리하는 것이 좋다.)

Shrink의 자세한 이론과 테스트는 아래의 내용을 참고하기 바란다.


어떤 세그먼트를 위해 공간이 크게 할당된 경우 High Water Mark 이후의 공간은 사용되지 않은 채로 남아 있게 될 수 있다. 또한 High Water Mark 이전의 영역에도 누적된 delete 연산의 결과로 빈 공간이 존재할 수 있다. 이 경우 다음과 같은 문제점이 있음을 알 수 있다:

  • 데이터가 보다 많은 블록들에 걸쳐 흩어져 있으므로 스캔시 보다 많은 I/O가 필요하다.
  • 내부 단편화로 인해 row-chaining/row migration이 일어날 가능성이 높다.
  • 전체적인 공간 낭비가 발생한다.

Oracle9i에서 이러한 문제점들을 해결하는 방안은 해당 오브젝트를 이동하거나 재생성하는 것이었다. Oracle Database 10g에서는 이 문제를 위해 Segment Shrink 기능을 추가적으로 제공한다.

한편 Oracle Database 10g의 Advisory framework는 Segment의 공간 사용에 관하여 각종 통계 보고 및 Segment Shrink를 포함한 권고안 제시를 위해 Segment Advisor를 제공한다.

Segment Shrink의 원리

Segment Shrink는 다음의 두 단계에 걸쳐 이루어진다.

  • 데이터의 compact
    • 다만, 실제 데이터가 바뀌는 것은 아니기 때문에 DML 트리거가 정의되어 있다 하더라도 발생하지 않는다.
    • Segment Shrink가 row-chaining을 완전히 제거하는 것을 보장하는 것은 아니다.
    • 보통의 DML과 같은 방식으로 이루어지므로 인덱스 dependency는 자동으로 처리된다. 다만 IOT에 대한 2차 인덱스는 shrink 직후 재생성하는 것을 권장한다.
  • 이 단계는 HWM 아래 영역에 있는 hole들을 채우는 작업이다. 이는 내부적으로 INSERT/DELETE 연산에 의해 이루어진다: HWM에 가까이 있는 행을 안쪽의 빈 공간을 찾아 INSERT하고, 그것이 끝나면 해당 행을 DELETE함으로써 행을 옮기는 것이다.
  • HWM의 push down
  • 1번 단계에 의해 데이터는 HWM에서 먼 쪽에 촘촘히 채워져 있을 것이고, 반대로 HWM에서 가까운 쪽의 공간은 비어 있는 상태가 된다. 이제 HWM를 내리고, 새롭게 설정된 HWM 이후의 모든 공간을 해당 테이블스페이스에 반납함으로써 segment shrink가 완료된다.

Segment Shrink는 online이자 in-place 연산이다. 1번 단계에서는 통상의 row-level lock이 필요할 뿐, 다른 세션의 DML을 불허하는 것은 아니기 때문에 오브젝트의 가용성은 제한되지 않는다. 또한 2번 단계에서 HWM를 내리는 데 필요한 exclusive 테이블 lock은 매우 짧은 시간 동안만 필요하다. 한편 Segment Shrink가 Oracle9i의 online redefinition과 다른 점은 별도의 임시 공간이 없이 바로 그 오브젝트에 대해서 (in-place) 수행될 수 있다는 점이다.

Segment Shrink의 조건

  1. 오직 Automatic Segment Space Management(ASSM)를 사용하는 테이블스페이스 내의 세그먼트만이 shrink될 수 있다. 데이터의 compaction 정보는 세그먼트 헤더의 bitmap block을 이용하기 때문이다. 다만 다음의 세그먼트들은 ASSM 테이블스페이스 내에 있더라도 shrink될 수 없는 제한이 있다:
  • 임시 세그먼트 및 Undo 세그먼트
  • 클러스터 내의 테이블
  • LONG 컬럼을 가진 테이블
  • ROWID 기반의 materialized view가 정의된 테이블
  • LOB 인덱스
  • IOT mapping 테이블
  • IOT overflow 세그먼트
  • 공유된 LOB 세그먼트

2. 데이터 compaction 단계에서 rowid가 변경되므로 해당 세그먼트에 대해 미리 ROW MOVEMENT가 enable되어 있어야 한다.

SHRINK SPACE 명령

테이블 세그먼트에 대한 segment shrink 명령은 다음과 같다:

ALTER table table_name SHRINK SPACE [COMPACT] [CASCADE];
  • 물론 테이블 뿐만 아니라 segment shrink를 지원하는 모든 오브젝트들에 대해 위와 같은 명령을 사용할 수 있다.
  • COMPACT 옵션이 지정된 경우 segment shrink는 1단계인 데이터 compaction까지만 수행되게 된다.
  • CASCADE 옵션이 지정된 경우 segment shrink는 dependent한 오브젝트들에 대해서도 자동으로 수행되게 된다. 예를 들면 테이블을 shrink하면서, 그 테이블에 대해 정의된 인덱스들 또한 자동으로 동시에 shrink할 수 있다.

Segment Advisor

Segment Advisor는 Segment Shrink를 포함한 Segment 관리를 위해 EM에서 제공하는 GUI이다. 이는 EM의 테이블스페이스 페이지, 스키마 오브젝트 페이지, 그리고 Advisor Central 페이지 중 하나로부터 access할 수 있다.

Segment Advisor의 기능은 다음과 같으며 필요한 자료들은 AWR로부터 제공받는다.

  • Segment Shrink
  • Segment Advisor는 어떤 오브젝트가 shrink 연산을 위한 좋은 후보인지를 권고한다. 이러한 결정은 그 세그먼트에 할당되었으나 사용되지 않는 공간의 크기, 세그먼트의 공간 사용 경향 등에 근거한다.
  • Growth Trend Report
  • 세그먼트의 공간 사용 경향을 보고함으로써 DBA의 용량 계획을 돕는다. 이는 나아가 Proactive Tablespace Monitoring 기능과 연동된다.
  • New Segment Resource Estimation
  • EM의 새로운 세그먼트 생성 페이지에는 "크기 예측" 버튼이 있어 이를 이용하면 필요한 디스크 크기를 예측할 수 있다. 이는 세그먼트의 구조, 예상되는 행의 수 등에 근거한다.

테스트

테스트 1: Segment Shrink

1. 테스트를 위해 테이블을 하나 생성하고 데이터를 입력해둔다.

SQL> conn scott/tiger
연결되었습니다.

SQL> create table employees as select * from hr.employees;

테이블이 생성되었습니다.

SQL> insert into employees select * from employees;

107 개의 행이 만들어졌습니다.

SQL> /

. . .

SQL> /

27392 개의 행이 만들어졌습니다.

SQL> commit;

커밋이 완료되었습니다.

2. 이제 employees 테이블이 얼마만큼의 공간을 차지하고 있는지를 확인해보자.

SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)) blocks from employees;
BLOCKS

-

556

SQL> select blocks, extents from user_segments where segment_name = ‘EMPLOYEES’;

BLOCKS EXTENTS

- -

640 20

첫번째 조회에서 얻는 blocks는 실제로 사용하고 있는 block의 개수를 나타낸다. 반면에 두번째 조회에서 얻은 blocks는 할당된 block의 개수, 즉 HWM를 나타낸다.

3. 이제 이 테이블에 "hole"을 만들자.

SQL> delete employees where department_id = 50;
23040 행이 삭제되었습니다.

SQL> commit;

커밋이 완료되었습니다.

4. 이제 HWM 아래에 많은 빈 공간이 생긴 employee 테이블을 shrink해보자.

SQL> alter table employees shrink space compact;
alter table employees shrink space compact

*

1행에 오류:

ORA-10636: ROW MOVEMENT is not enabled

5. ROW MOVEMENT는 default로 disable되어 있다. 이것을 수정하고 재시도 해보자.

 

6. Shrink space 명령에 compact 옵션을 주었다. 이는 데이터의 compaction만 일으키고, HWM는 그대로 두는 것을 의미한다. 이는 다음의 조회로 확인해볼 수 있다.

SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)) blocks from employees;
BLOCKS

-

304

SQL> select blocks, extents from user_segments where segment_name = ‘EMPLOYEES’;

BLOCKS EXTENTS

- -

640 20

실제 사용하는 block의 개수가 556개에서 304개로 늘었다. 다만 HWM는 640으로 변한 게 없다.

7. 이제 HWM까지 조정한 후 다시 결과를 확인해보자.

SQL> alter table employees shrink space;
테이블이 변경되었습니다.

SQL> select blocks, extents from user_segments where segment_name = ‘EMPLOYEES’;

BLOCKS EXTENTS

- -

320 18

HWM가 640 에서 320 으로 내려갔음을 확인할 수 있다.

 

테스트 2: Segment Advisor

1. 테스트를 위해 테이블스페이스 하나를 새로 생성한다.

SQL> create tablespace segment_test
2 datafile ‘D:\SW\oracle\oradata\cook\segment_test.dbf’ size 5m

3 logging

4 extent management local

5 segment space management auto;

테이블 영역이 생성되었습니다.

2. 테이블스페이스 임계값을 확인해보자.

SQL> select warning_value,
2 critical_value,

3 object_name

4 from dba_thresholds

5 where metrics_name = ‘Tablespace Space Usage’;

WARNING_VALUE CRITICAL_VALUE OBJECT_NAME

– – –

85 97

 

기본값을 그대로 쓰고 있음을 알 수 있다. 이제 1번에서 생성한 테이블스페이스에 대해 warning 및 critical value를 각각 50, 60으로 수정하자.

SQL> exec dbms_server_alert.set_threshold(9000, dbms_server_alert.OPERATOR_GT, 50, dbms_server_alert.OPERATOR_GT, 60, 1, 1, null, dbms_server_alert.OBJECT_TYPE_TABLESPACE, ‘SEGMENT_TEST’);
PL/SQL 처리가 정상적으로 완료되었습니다.

SQL> select warning_value,

2 critical_value,

3 object_name

4 from dba_thresholds

5 where metrics_name = ‘Tablespace Space Usage’;

WARNING_VALUE CRITICAL_VALUE OBJECT_NAME

– – –

50 60 SEGMENT_TEST

85 97

3. 이제 이 테이블스페이스 내에 테이블을 하나 생성하여 데이터를 충분히 입력한다. 그리고 DELETE 연산을 통해 hole을 만든다.

SQL> conn scott/tiger
연결되었습니다.

SQL>

SQL> create table employees1 tablespace segment_test as select * from hr.employees;

테이블이 생성되었습니다.

SQL> create table employees2 tablespace segment_test as select * from hr.employees;

테이블이 생성되었습니다.

SQL> create table employees3 tablespace segment_test as select * from hr.employees;

테이블이 생성되었습니다.

SQL> create table employees4 tablespace segment_test as select * from hr.employees;

테이블이 생성되었습니다.

SQL> create table employees5 tablespace segment_test as select * from hr.employees;

테이블이 생성되었습니다.

SQL> begin

2 for i in 1..5 loop

3 insert into employees1 select * from employees1;

4 insert into employees2 select * from employees2;

5 insert into employees3 select * from employees3;

6 insert into employees4 select * from employees4;

7 insert into employees5 select * from employees5;

8

9 commit;

10 end loop;

11 end;

12 /

PL/SQL 처리가 정상적으로 완료되었습니다.

SQL> insert into employees1 select * from employees1;

3424 개의 행이 만들어졌습니다.

SQL> insert into employees2 select * from employees2;

3424 개의 행이 만들어졌습니다.

SQL> insert into employees3 select * from employees3;

3424 개의 행이 만들어졌습니다.

SQL> commit;

커밋이 완료되었습니다.

4. 많은 행이 입력되었으므로 잠시 후 다음과 같은 alert가 생성되었음을 확인할 수 있다.

SQL> select reason from dba_outstanding_alerts;
REASON



Tablespace [SEGMENT_TEST] is [52 percent] full

5. 여기서 미리 3번에서 다루었던 테이블들 중 일부에 대해 ROW MOVEMENT를 enable시켜 둔다.

SQL> alter table employees1 enable row movement;
테이블이 변경되었습니다.

SQL> alter table employees2 enable row movement;

테이블이 변경되었습니다.

SQL> alter table employees3 enable row movement;

테이블이 변경되었습니다.

6. 이제 EM의 Advisor Central 링크를 이용하여 Segment Advisor에 접속하자.

대상으로 테이블스페이스를 선택하고, 분석은 Comprehensive 모드를 선택한 후 "계속"을 클릭한다.

Add를 클릭한다.

테스트 대상인 segment_test를 선택하고 확인을 클릭한다.

다음을 클릭한다.

다음을 클릭한다.

다음을 클릭한다.

Submit을 클릭한다.

잠시 후 Advisor Central 페이지에서 다음과 같이 방금 Submit했던 분석 작업이 완료되었음을 확인할 수 있다.

결과 보기를 클릭하면 Segment Advisor가 Employees1, 2, 3 테이블에 대해 Segment Shrink를 할 것을 권고하는 내용을 확인할 수 있다.

 

7. 이제 employees1, 2, 3 세개 테이블에 대해 shrink를 수행하자.

SQL> alter table employees1 shrink space;
테이블이
변경되었습니다.

SQL> alter table employees2 shrink space;

테이블이
변경되었습니다.

SQL> alter table employees3 shrink space;

테이블이
변경되었습니다.

8. 잠시 후 아까 발생하였던 alert가 해제되었음을 알 수 있다.

SQL> select reason from dba_outstanding_alerts;
선택된
레코드가
없습니다.

Oracle10g 이후 버전에서 Segment Shrink 기능을 사용하면 효율적인 방법으로 테이블스페이스 내의 공간 낭비를 줄이고 그에 따라 성능을 높일 수가 있다.

또한 이를 Segment Advisor가 제공하는 GUI를 통해 사용할 수 있으므로 더욱 간편하다.

Posted by 목표를 가지고 달린다
,

온라인 서비스는 멀티프로세스로 인해, 개별 거래의 속도가 느릴지라도 사용자가 느낄 만큼 속도가 느린 경우는 없다. 물론 조회시 where 조건들이 index에 등록되어 있지 않다면, 처음에는 속도가 느린 것을 느끼지 못할지라도 ... 자료가 쌓이면 속도가 느린 것을 느낄 것이다.

 

그럼 실행 쿼리의 실행시간 기준으로 TOP 10을 조회하여, 해당 where 조건에 항목들에 대해 인덱스를 생성해주면 된다.

인덱스 생성시에 모든 조건을 인덱스로 만들어서는 안된다. 데이터 1건인데, 인덱스가 10개면 실제 11개의 처리가 발생하므로, 속도저하가 발생하고 인덱스 실행 계획이 원하지 예상하지 못하는 방식으로 나와 문제가 될 수 있다.

인덱스는 무조건 5개 이하이다.

왠만하여 공통 인덱스는 모든 업무를 커버할 수 있도록 선정하고, 조회는 인덱스만 잘 설정되어 있다면 문제 없다. 

만약, 배치업무를 수행하는데 느리다면, 다음 사항을 체크해 보자.

1. 조회시 인덱스를 이용하는지?
2. Array 작업을 수행하는지? 
3. 중간중간 commit 을 수행할 수 있는지? 
4. Counter 체크 
5. 통계 정보 생성 
6. 불필요한 과거 정보 삭제
7. 업무 프로세스 변경

1. 조회시 인덱스를 이용하는지? 또는 TABLE FULL SCAN 을 하는지? 만들었다고 생각하지 말고, 체크해보자. 그리고 인덱스는 순차적으로 차례대로 찾기 때문에 항목이 5개인 인덱스는 중간에 3번 항목이 없다면, 결국 1번과 2번 항목만 인덱스를 읽고 나머지는 range_scan을 하기 때문에 데이터량에 따라 항목 조절을 해야 한다.

2. Array 작업을 수행하는지? 대량의 작업은 기본적으로 다량 Fetch, 일괄 Insert(또는 Update)를 수행해야 속도가 빠르다. execute() * 10000 보다는 batch_Execute() * 5 가 몇십배 빠르다.

3. 중간중간 commit 을 수행할 수 있는지? 업무에 따라, 중간에 commit을 할수 있다면, 몇천건 또는 몇만건 단위로 commit을 수행한다면 재작업시 작업량을 줄일 수 있다. 검토 후 중간에 commit을 삽입하자.

4. Counter 체크 : 오라클의 sequence를 사용하지 않고, select max(seq) from tableA; 사용한다면, 당장 변경하라.
* 혹시 개발자 중에서 SELECT TASEQ.nextval from BigTable where rownum =1; 로 개발했다면, 당장 변경하라.
SELECT TASEQ.nextval from dual; 로 실제 수행속도는 테이블의 사이즈에따라 몇백배까지 차이 난다.

5. 통계 정보 생성 : 통계정보가 최신화 되지 않아 plan이 느릴 수 있으므로, Analyze 해보자.

6. 불필요한 과거 정보 삭제 : 데이터의 사이즈에 따라, 성능이 저하될 수 도 있으므로 과거 정보 삭제나 parition 나누자.

7. 업무 프로세스 변경 : DB에서 index 타고, 기본적인 속도개선까지 했다면 프로세스 변경을 고려해 보자. 여기까지 한 후, 하드웨어 증설을 고려하자.

# 추가 설명. sql 구성요소들은 아래와 같은 순서로 실행 된다

1) FROM, WHERE 절을 처리
2) ROWNUM 조건 적용
3) SELECT COLUMN LIST 절을 적용
4) GROUP BY 절을 적용
5) HAVING 절을 적용
6) ORDER BY 절을 적용

그러므로, 4번의 예시처럼 의미없이 대량의 테이블에서 rownum <=1 을 하면, 대량의 자료를 fetch 한후 nextval을 가져오는 불필요한 작업이 발생하므로, dual을 적절히 사용하자.


추가 tip. SMS 제품에서는 Oracle에서 제공하 v$sql, DBA_HIST_SQLSTAT, DBA_HIST_SQLTEXT, DBA_HIST_SNAPSHOT 등의 테이블을 이용하여, TOP N Query(상위 N개의 쿼리)를 제공한다. 이것을 바탕으로 지연 서비스의 쿼리 실행계획 및 실행 단위의 소요시간까지 제공해준다. SMS제품이 제공해 주는 것외에 본인이 DBA 또는 고급 개발자로써, 서비스 품질을 위한다면, 아래의 내용을 참고하여 개선 대상을 찾아 고민해보자.

다만, 아래의 것은 여러분이 문제를 찾기 위한 Query일 뿐, 해결방법은 각양각색이므로 획일적으로 답할 순 없다.

반복하는 쿼리 중에서 총 수행시간이 긴 쿼리 찾기.
(짧은 업무일지라도, 단일 프로세스로 처리되면 문제가 된다. 예를 들어, 30msec * 100만번이면, 300,00초= 6,000분 = 100시간이 된다.)

SELECT * FROM (
SELECT S.SQL_ID, ROUND(SUM(CPU_TIME_DELTA)/100000) CPUTIME, SUM(EXECUTIONS_DELTA) TOTAL_EXECUTED,
DBMS_LOB.SUBSTR(SQL_TEXT,2000,1) SQLTEXT
FROM DBA_HIST_SQLSTAT H, DBA_HIST_SQLTEXT S, DBA_HIST_SNAPSHOT T
WHERE S.SQL_ID = H.SQL_ID
AND H.SNAP_ID = T.SNAP_ID
AND T.BEGIN_INTERVAL_TIME BETWEEN TO_DATE('20190513 09:00:00','YYYYMMDD HH24:MI:SS') AND TO_DATE('20190514 15:00:00','YYYYMMDD HH24:MI:SS')
GROUP BY S.SQL_ID, DBMS_LOB.SUBSTR(SQL_TEXT,2000,1) ORDER BY 3 DESC
)
WHERE rownum < 21 and CPUTIME > 1000 ;


ORACLE서버에서 수행시간이 긴 쿼리 찾기 쿼리
SELECT ROWNUM NO,
PARSING_SCHEMA_NAME,
to_char(ELAPSED_TIME/(1000000 * decode(executions,null,1,0,1,executions)),999999.9999 ) 평균실행시간,
executions 실행횟수,
SQL_TEXT 쿼리 ,
SQL_FULLTEXT
FROM V$SQL
WHERE LAST_ACTIVE_TIME > SYSDATE-(1/24*2)
-- AND LAST_ACTIVE_TIME BETWEEN to_Date('20111226163000','YYYYMMDDHH24MISS') AND to_Date('20111226170000','YYYYMMDDHH24MISS')
-- AND ELAPSED_TIME >= 1 * 1000000 * decode(executions,null,1,0,1,executions)
and PARSING_SCHEMA_NAME = 'ZIPCODE'
ORDER BY 평균실행시간 DESC, 실행횟수 DESC;


SELECT TO_CHAR (SID) sid, serial# serialNumber,
SUBSTR (TO_CHAR (last_call_et), 1, 6) executeSeconds, userName, machine,
b.sql_text sqlText
FROM v$session a, v$sqltext b
WHERE username NOT IN ('SYSTEM', 'SYS')
AND a.TYPE != 'BACKGROUND'
AND a.status = 'ACTIVE'
AND a.sql_address = b.address(+)
AND a.sql_hash_value = b.hash_value(+)
ORDER BY a.last_call_et DESC, a.SID, a.serial#, b.address, b.hash_value, b.piece


현재 실행되고 있는 쿼리 와 실행 시간

SELECT TO_CHAR (SID) sid, serial# serialNumber,
SUBSTR (TO_CHAR (last_call_et), 1, 6) executeSeconds, userName, machine,
b.sql_text sqlText
FROM v$session a, v$sqltext b
WHERE username NOT IN ('SYSTEM', 'SYS')
AND a.TYPE != 'BACKGROUND'
AND a.status = 'ACTIVE'
AND a.sql_address = b.address(+)
AND a.sql_hash_value = b.hash_value(+)
ORDER BY a.last_call_et DESC,
a.SID,
a.serial#,
b.address,
b.hash_value,
b.piece

Posted by 목표를 가지고 달린다
,

//이미지 뷰를 보여줌

ImageView.setVisibility(View.VISIBLE);

//이미지뷰 안보이게(공간은 남음)

ImageView.setVisibility(View.INVISIBLE);

//이미지뷰 아예 숨기기 공간조차 없어짐

ImageView.setVisibility(View.GONE);

2. ViewPage를 이용한 페이지 만들기 : https://yoo-hyeok.tistory.com/58?category=708422

2. Customized RadioButton : https://yoo-hyeok.tistory.com/57?category=708422

2. RadioButton : https://yoo-hyeok.tistory.com/55?category=708422

2. ListView 하기..리스트를 커스컴마이즈.. : https://yoo-hyeok.tistory.com/53?category=708422

2. Customized Dialog 하기 : https://yoo-hyeok.tistory.com/51?category=708422

2. 문자만 표시하는 Dialog 하기 : https://yoo-hyeok.tistory.com/50?category=708422

2. gif 이미지 넣기(동영상보다는 gif가 좋을 듯) : https://yoo-hyeok.tistory.com/48?category=708422

2. 최근 splash 방식 : velog.io/@pish11010/Android-Splash-Screen-%EA%B5%AC%ED%98%84

[Android] Splash Screen 구현

Splash Screen 은 일반적으로 앱이 실행될 때 나타나는 화면입니다.YouTube 앱 실행 시 나오는 잠깐 로고화면이 나오고 앱 메인화면으로 진입되는데, 여기서 로고가 나온 화면이 Splash Screen 입니다.이

velog.io

2. 어플 대표 화면 넣기 : https://yoo-hyeok.tistory.com/31?category=708422

[Android] 안드로이드 Splash Activity (어플 설명 액티비티, 어플 대표 화면) 만들기

카카오톡 실행시켜보면 처음에 카카오톡 이미지가 나오고 1초뒤에 카톡이 실행됩니다. 어플리케이션의 대표 레이아웃을 넣어 어플리케이션의 이미지를 담당하는 액티비티입니다. 만드는 방법은 간단합니다. 프로젝..

yoo-hyeok.tistory.com

3. 백버튼 눌렀을 때 알림창. https://yoo-hyeok.tistory.com/32?category=708422

유혁의 엉터리 개발

소프트웨어 개발자

yoo-hyeok.tistory.com

4. Json 사용 법 : https://yoo-hyeok.tistory.com/37?category=708422

[Android] 안드로이드 JSON 문자열 파싱(parsing)

String JSONData = "{"school":[{"subject1":"math"},{"subject2":"korean"}],"name":"유혁"}" (문법 생략) 안드로이드 스튜디오에서 파싱하기 ArrayList ArrList = new ArrayList(); //어레이 리..

yoo-hyeok.tistory.com

5. firebase push 이용법 : https://yoo-hyeok.tistory.com/43?category=708422

[Android] Firebase(Google Cloud Message) 를 이용한 푸시알림 구현 - (1) 환경설정

휴대폰 게임을 하다보면 중간중간에 아이템이 왔다며 푸시알림을 많이 받아보셨을 겁니다. 안드로이드 개발중에 이런 푸시알림을 주고싶을 때 GCM을 사용합니다. Firebase가 최근에 나온 버전이고 Firebase 만으로..

yoo-hyeok.tistory.com

Posted by 목표를 가지고 달린다
,

1. 스마트폰은 기본적으로 일정 시간동안 아무런 반응이 없으면 자동으로 화면이 꺼지게 됩니다.

원할 경우 실행되는 동안 화면을 안꺼지 게 할수 있습니다.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
을 추가하게 되면 실행되는 동안 화면이 꺼지지 않습니다.

2. Dialog 타이틀바 없애기.

3. EditText에 이벤트 주기

EditText 이벤트는 addTextChangedListener() 를 사용하면 보다 쉽게 다룰수가 있었다.( setOnClickListener() 보다 좋음.)

et.addTextChangedListener(new TextWatcher(){   

   public void afterTextChanged(Editable arg0) {
    // TODO Auto-generated method stub    
   }   

   public void beforeTextChanged(CharSequence s, int start, int count,
     int after) {
    // TODO Auto-generated method stub    
   }

   public void onTextChanged(CharSequence s, int start, int before,
     int count) {
    // TODO Auto-generated method stub
    
   }
         
});

4. intent : https://yoo-hyeok.tistory.com/15?category=708422 putExtra를 단일 String, ArrayList 모두 가능.

5. 서비스 등록하기

Service는 background에서 처리를 계속할 수 있는 클래스이다.
Service는 기본적으로 activity를 가지지 않는다.

서비스를 구현하기 위한 3가지 절차
-- Service 클래스를 확장한 새로운 클래스 정의
-- Manifest file에 Service 선언 추가
-- App에서 Service 실행



1. 서비스를 실행하는 클래스 - 타이머를 이용한 반복 처리.

public class MyService extends Service implements Runnable {

    // 시작 ID
    private int mStartId;
    // 서비스에 대한 스레드에 연결된 Handler. 타이머 이용한 반복 처리시 사용.
    private Handler mHandler;
    // 서비스 동작여부 flag
    private boolean mRunning;
    // 타이머 설정 (2초)
    private static final int TIMER_PERIOD = 2 * 1000; 
    private static final int COUNT = 10;
    private int mCounter;


    // 서비스를 생성할 때 호출
    public void onCreate() {
        Log.e("MyService", "Service Created.");
        super.onCreate();
        mHandler = new Handler();
        mRunning = false;
    }


    // 서비스 시작할 때 호출. background에서의 처리가 시작됨.
    // startId : 서비스 시작요구 id. stopSelf에서 종료할 때 사용. 

     //onStart는 여러번 호출될 수 있기 때문에 식별자로 사용.

    public void onStart(Intent intent, int startId) {
        Log.e("MyService", "Service startId = " + startId);
        super.onStart(intent, startId);
        mStartId = startId;
        mCounter = COUNT;

        // 동작중이 아니면 run 메소드를 일정 시간 후에 시작
        if (!mRunning) {
              // this : 서비스 처리의 본체인 run 메소드. Runnable 인터페이스를 구현 필요.
              // postDelayed : 일정시간마다 메소드 호출
              mHandler.postDelayed(this, TIMER_PERIOD);
              mRunning = true;
        }
    }

 

    // 서비스의 종료시 호출
    public void onDestroy() {
        // onDestroy가 호출되어 서비스가 종료되어도 
        // postDelayed는 바로 정지되지 않고 다음 번 run 메소드를 호출.
        mRunning = false;
        super.onDestroy();
    }



    // 서비스 처리
    public void run() {
        if (!mRunning) {
            // 서비스 종료 요청이 들어온 경우 그냥 종료
            Log.e("MyService", "run after destory");
            return;
        } else if (--mCounter <= 0) {
            // 지정한 횟수 실행하면 스스로 종료
            Log.e("MyService", "stop Service id = "+mStartId);
            stopSelf(mStartId);
        } else {
            // 다음 작업을 다시 요구
            Log.e("MyService", "mCounter : " + mCounter);
            mHandler.postDelayed(this, TIMER_PERIOD);
        }
    }

    // 원격 메소드 호출을 위해 사용
    // 메서드 호출을 제공하지 않으면 null을 반환
    public IBinder onBind(Intent intent) {
        return null;
    }
}




2. 서비스 실행, 종료를 사용자가 요청하는 클래스

// 서비스 시작과 종료를 요구하는 Activity
public class MyServiceActivity extends Activity {

    ComponentName mService;    // 시작 서비스의 이름
    TextView mTextView;              // 서비스 상태 표시



    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        mTextView = (TextView)findViewById(R.id.text_view);
        
        Button start = (Button)findViewById(R.id.start_button);
        start.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                startHelloService();
            }});
        
        Button stop = (Button)findViewById(R.id.stop_button);
        stop.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                stopHelloService();
            }});
    }



    // 서비스 시작 요청
    private void startHelloService() {
        mService = startService(new Intent(this, MyService.class));
        mTextView.append(mService.toShortString()+" started.\n");
    }

 

    // 실행한 서비스 중지 요청

    private void stopHelloService() {
        if (mService == null) {
            mTextView.append("No requested service.\n");
            return;
        }
        
        Intent i = new Intent();
        i.setComponent(mService);
        if (stopService(i))
            mTextView.append(mService.toShortString()+" is stopped.\n");
        else
            mTextView.append(mService.toShortString()+" is alrady stopped.\n");
    }
}


3. 사용자가 서비스 실행, 종료하는 화면 구성

<!-- 시작 -->
<Button android:id="@+id/start_button" android:text="Start"
android:layout_width="fill_parent" android:layout_height="wrap_content" />

<!-- 종료 -->
<Button android:id="@+id/stop_button" android:text="Stop"
android:layout_width="fill_parent" android:layout_height="wrap_content" />

<!-- 상태표시 -->
<TextView android:id="@+id/text_view_id"

android:editable="true"
android:layout_width="fill_parent" android:layout_height="fill_parent" />

6. 컴포넌트의 생명주기
컴포넌트의 생명주기는 컴포넌트를 인스턴스화 할 때 시작해서, 인스턴스가 사라질 때 종료됩니다.
액티비티의 경우 그 사이에 활성화, 비활성화가 될 수 있기 때문에 사용자에게 보이거나 , 또는 보이지 않을 수도 있습니다.

1. 액티비티 생명주기


액티비티는 필수적으로 세 가지의 상태를 가지고 있습니다.

▣ 활성화(activity) 또는 실행 (running) 상태

액티비티가 포그라운드 화면으로 사용자에게 보이는 상태입니다 ( 즉, 현재 태스크에서 스택의 최상위에 위치하는 것).
이 상태는 사용자 액션을 받을 수 있게 됩니다.


▣ 멈춤(paused) 상태

사용자 액션을 받진 못하지만 여전히 보여지고 있는 상태입니다. 즉 다른 액티비티가 그 위에 위치하지만 해당 액티비티가 화면을 전부 채우지 않거나 투명해서 멈춤 상태의 액티비티를 볼 수 있는 상태입니다.
이 상태의 액티비티는 살아있습니다 ( 모든 상태정보와 멤버를 유지 중 )
하지만 , 메모리 부족시엔 시스템에 의해 강제종료 될 수 있습니다.


▣ 정지 (stopped) 상태

완전히 다른 액티비티에 의해 가려진 상태입니다.더 이상 사용자에게 보이진 않지만 여전히 살아서(정보와 멤버유지) 있는 상태이죠.
여전히 보여지진 않기 때문에 메모리 부족시엔 강제종료 될 수 있습니다.



액티비티가 멈춤 또는 정지 상태라면, 시스템은 finish() 메소드를 호출하거나 프로세스를 강제종료 시킴으로서 메모리에서 제거할 수 있습니다.
종료된 액티비티가 다시 실행된다면, 다시 시작되어야 하고 이전 상태로 복구되어야 할 것입니다.



액티비티 상태변화


액티비티의 상태가 변하면 아래의 메소드가 호출됨으로써 변화가 통보되는데요.
이 메소들은 모두 프로텍티드(protected) 메소드 입니다.


여기의 7가지 메소드들은 오버라이드 할 수 있습니다.
단, 모든 액티비티는 최초 인스턴스 초기화를 위해 onCreate() 메소드는 무조건 구현해야 합니다.

또한, 액티비티 종료직전.... 마지막 기회가 될 수도 있는 시점에선 적절한 데이터 저장을 위해 onPause() 메소드도 구현해주면 좋겠네요.

액티비티 생명주기 메소드를 구현할 땐 항상 슈퍼클래스 버전을 호출하여야 합니다.
protected void onPause() {

super.onPause() ;

}


네스티드 루프(nested loop)


액티비티 생명주기 메소드를 구현하여 볼 수 있는 것은 아래와 같습니다.

▣ 액티비티 인타이어 라이프타임 ( entire lifetime )

onCreate() 와 onDestroy() 메소드 사이에서 발생합니다.
액티비티는 onCreate() 메소드에서 모든 초기 설정을 하고 onDestroy()에서 모든 리소스를 해제하죠.


▣ 액티비티 비지블 라이프타임 ( visible lifetime )

onStart() 메소드에서 onStop() 메소드 사이에서 발생합니다.
onStart() 메소드에서는 사용자 인터페이스의 변화 모니터를 위해 브로드캐스트 리시버를 등록할 수 있고 사용자가 보고있는 화면이 없을때엔 onStop() 메소드에서 제거할 수 있습니다. onStart() 와 onStop()은 액티비티가 사용자에게 보여지고 숨겨지는 상태이므로 여러번 호출 될 수 있습니다.


▣ 액티비티 포그라운드 라이프타임 ( foreground lifetime )

onResume() 메소드와 onPause() 메소드 사이에서 발생합니다.
이 기간동안 액티비티는 화면에서 다른 모든 액티비티보다 앞에 놓이며 사용자에게 보여집니다. onPause()는 기계가 꺼지거나 새로운 액티비티가 시작될 때 호출되고, onResume() 은 액티비티가 다시 복귀되거나 새로운 인텐트가 도착했을때 호출됩니다.
따라서 이 두개의 메소드 내용은 빠르고 가벼울 수록 좋겠네요.



생명주기 메소드가 하는 일

▣ onCreate()

액티비티가 최초 생성시에 호출됩니다. 초기화 설정을 하는 곳이지요. 보관된 상태의 액티비티가 있다면, 그 상태를 저장중인 Bundle 객체를 받습니다.
onStart() 메소드가 이어집니다. 강제종료가 불가능 합니다.


▣ onRestart()

액티비티가 정지 후 다시 시작되기 바로 직전에 호출됩니다.
onStart() 메소드가 이어집니다. 강제종료가 불가능 합니다.


▣ onStart()

액티비티가 사용자에게 보여지기 직전에 호출됩니다.
액티비티가 보여지게되면 onResume() 메소드가, 안보이게 되면 onStop() 메소드가 이어집니다.
강제종료가 불가능 합니다.


▣ onResume()

액티비티가 사용자와 상호작용하기 직전에 호출됩니다 (스택의 최상위에 위치)
onPause() 메소드가 이어집니다. 강제종료가 불가능 합니다.


▣ onPause()

시스템이 다른 액티비티를 시작하려 할 때 호출됩니다.
일반적으로 데이터 저장을 하기에 좋은 곳입니다.
하지만 소스코드의 속도가 빨라야합니다.
왜냐하면 이 메소드가 끝나기 전까진 다음 액티비티가 실행되지 않기 때문인데요,
액티비티가 되돌아오면 onResume(), 보이지않게되면 onStop() 이 이어집니다.
강제종료가 가능 합니다.


▣ onStop()

액티비티가 사용자에게 보이지 않을때 호출 됩니다.
액티비티가 제거되거나 다른 액티비티가 실행되어 해당 액티비티를 덮어버렸을 때, 호출되죠. 액티비티가 되돌아오면 onRestart(), 액티비티가 사라지면 onDestroy() 가 이어집니다.
강제종료가 가능 합니다.


▣ onDestroy()

액티비티 삭제 직전에 호출됩니다. 액티비티가 받는 마지막 호출 메소드가 되죠. 시스템이 메모리 확보를 위해 액티비티 인스턴스를 없애버려고 하거나 , finish() 메소드가 호출되면 호출되는 메소드입니다.

isFinishing() 메소드로 두 가지를 분기할 수 있습니다.



onStart() 메소드가 이어집니다. 강제종료가 불가능 합니다.



☞ 여기에서 onPause() 는 프로세스가 강제종료 되기 전에 호출되는 것입니다. 즉, 프로세스가 강제종료 될 때 onPause() 는 무조건 호출되는 유일한 곳이 됩니다. ( onStop(), onDestroy() 는 호출되지 않을 수 있어요 ), 따라서 이터 저장 등의 작업은 종료되기 직전에 호출되는 onPause() 에 구현해야 되겠네요.


액티비티 상태 저장하기


시스템이 액티비티를 강제종료 했을때, 사용자는 이전의 액티비티로 돌아가고 싶을 수 있습니다. 이럴 경우 액티비티가 강제종료 되기 전에 상태를 저장할 수 있는 onSaveInstanceState() 메소드를 구현하면 저장이 가능해 집니다.



즉, 액티비티가 파괴되기전에 호출되는 메소드 인데요. ( onPause() 호출 이전에 호출됩니다. )
이 메소드는 이름/값 쌍으로 이루어진 번들 객체(Bundle) 를 인수로 가집니다. 액티비티가 다시 시작되면 번들은 onSaveInstanceState() 와 onStart() 이후에 호출되는 onRestoreInstanceState() 에게 전달됩니다.



☞ onSaveInstanceState() , onRestoreInstanceState() 메소드는 생명주기 메소드는 아닙니다.
따라서 항상 호출되지는 않으며 특정 상황 ( 액티비티 강제종료전에 onSaveInstance() 호출처럼 ) 에서만 호출됩니다. 단, 사용자 액션에 의해 종료될 때는 ( 사용자가 직접종료 ) 호출되지 않습니다.
- 사용자가 되돌아가지 않을 생각으로 종료한 것으로 판단한 것이겠죠...

onSaveInstanceState() 는 액티비티의 일시적인 상태 저장을 위한 것이므로 , 데이터 등을 안전하게 저장하려면 onPause() 메소드에서 처리해야 합니다.


액티비티 생명주기 메소드의 순서


하나의 액티비티가 다른 액티비티를 시작할 때 하나는 멈추고 정지되며, 다른 하나는 시작되는 구조를 가집니다. 생명주기 메소드의 순서는 두 개의 액티비티가 동일 프로세스 안에 있을 때에 정의됩니다.

1. 현재 액티비티("A") 의 onPause() 가 호출됩니다.
2. 다음 시작되는 액티비티("B") 의 onCreate() -> onStart() -> onResume() 이 차례대로 호출됩니다
3. "B" 액티비티가 더 이상 사용되지 않으면 그것의 onStop() 이 호출됩니다.

7. PHP MySql 설치 등.. https://yoo-hyeok.tistory.com/16?category=708422

Posted by 목표를 가지고 달린다
,

Head First 시리즈는 "생각하게 만드는 책"이다. 요즘 인터넷이 발달하고 많은 자료, 샘플 자료들이 널려 있기에 검색해서 사용하면 느리지만 가능하다. 기술은 없으나 기교를 키울 수 있다.

하지만, 본 시리즈는 개발자에게 왜 이렇게 구동하는지? 이렇게 하면 어떤 이익과 문제점이 있는지를 잘 구분해서 알려준다. 기술서적이라기 보다는 산책하는 기분으로 읽기에 1주일 이내에 빠르게 봐야 의미가 있다.

해당 시리즈는 여러권 읽어 보았으나, 오늘은 Ajax에 대해 쓰기로 한다.

Ajax는 java script를 활용하여 DOM, JSON, XML을 활용하는 기법이다.

즉 특별한 기법이라기 보다는 특화(?)된 기법이라고 하는게 맞다. 이책 Head First 특성상 디테일한 내용보다는 개념을 잡는 책이다.

기존 JavaScipt 를 사용해본 사람이면, 예를 들어

<html>

<Head>

<script language="javascript">

 function example() {

      var dev1 = "1";

      dev2      = "2";

       .........

      }

</script>

<body onload = example();>

이런식으로 활용했을 것이다.

최초 화면 로딩시 특정 함수를 실행하는 방법은 2가지이다.

1. 위의 예제처럼 body 태그안에 onload= "함수"를 명시.

2. 스크립트 정의하는 부분에

window.onload = example;

이라고 ()를 제외한 함수를 명시하는 것이다.

 

3. 변수 역시 var를 사용하지 않으면 해당 변수는 전역변수로 인식한다. 그래서 대부분 사용자가 함수정의시에 var를 사용해서

다른 함수와 변수가 겹치지 않도록 지역변수로 선언한 것이다. 이것 역시 funtion example() { .........} 구분 밖에서 선언하면,

var를 사용해서 선언하였다 하더라도 { } 밖에서 선언한 것이라 전역변수가 된다.

이것은 추후에 함수 사용시 변수를 재사용할 수 있는 여부를 결정짓기 때문에 중요하다.

# 예제 소스

function checkUsername() {

request = createRequest();

if(request == null )

alert("unable to create request");

} else {

var theName = document.getElementById("username").value;

var username = escape(theName); <----- 특수문자들을 처리하기 위해서 escape 함수로 변수 처리

var url = "checkName.php?username=" + username;

request.onreadystatechange = userNameChecked; <-----결과가 나오면 처리할 함수를 설정

request.open("GET", url , true); <-----get, post방식, url, true(비동기), false(동기) 방식.

request.send(null);

}

 

# 예제 소스

- 보여지는 부분과 기능을 구현하는 것을 구분하는 방법은 CSS를 활용하여 보여지는 것을 구분하는 것이다. 즉 클래스를 설정한 후,

자바스크립트로는 클래스를 변경해주면 된다.

CSS 파일...

#username {

background : #ff url .....

}

#username.checking { background :...}

#username.approved { backgroudn...}

 

# 예제소스

- 엘리먼트 찾기 : 엘리먼트들은 일종의 parent-child 관계이기 때문에 특정 element를 찾은 후, 다시 거기서 element검색이 가능하다.

function showTab() {

var selectedTab = this.title;

var images =

document.getElementById("tabs").getElementsByTagName("img"); <--- 특정 Element 안에 Element로 검색

for(var i =0 ; i < images.length; i++){

var currentImage = images[i];

}

}

# 예제소스

2개이상의 이벤트 등록하기

- 사파리, 파이어폭스,

currentBtn.addEventListener("mouseover", showHint, false);

currentBtn.addEventListener("mouseover", buttonOver, false);

- IE

currentBtn.attachEvent("onmouseover", showHint);

currentBtn.attachEvent("onmouseover", buttonOver);

- 1개만 등록시에는

currentBtn.onclick = showHint;

- 이벤트 제거방법

currentBtn.onclick = "";

 

# 예제소스

- this 가져오기.

브라우져마다 this를 가져오는 방식이 다르다. 위의 showTab() 에서 this를 해결해주는 방법.

function getActivatedObejct(e) {
var obj;
if(!e) {
//early version of IE
obj = window.event.srcElement;
} else if(e.srcElement) {
// IE 7 이상.
obj = e.srcElement;
} else {
// DOM Level 2 Browser
obj = e.target;
}
return obj;
}

 

# 1장의 전체 소스

붙임파일 참조.

if(passwordRequest.readyState == 4) { << -- 비동기전송의 결과가 옴.

if(passwordRequest.status == 200) { << -- 처리가 정상으로 됨.
if(passwordRequest.responseText == "okay") { << --결과값을 검증.

 

# 함수소개

1. t = setInterval(scrollImages, 50); (함수, 밀리초단위시간) << - 주기적으로 함수를 실행함.

2. var pieces = "Decide, Commit, Succeed".split(",");

alert(pieces[0] + "," +pieces[1] + "," +pieces[2] );

3. insertBefore(), appendChild()와는 달리 특정 엘리먼트 앞에 추가함.

4. removeChild()는 노드를 제거하는데, 마지막 노드부터 제거해야 함.

 

# DOM특징

모든 노드들은 parentNode라는 속성을 가지지만 parentNode 속성은 읽기 전용.

appendChild() 함수. --> Node.appendChild(element);

노드 관련 속성 : parentNode, firstChild, lastChild, childNodes, nextSibling, previousSibling, nodeName

이중에서 nodeName에 관하여...

엘리먼트 노드들은 엘리먼트 이름과 동일한 노드 이름을 지니고, 문자 노드의 노드이름은 "#text"이다.

즉 img 경우 nodeName은 img 이지만, 문자열은 "#text"이다.

 

# 프레임워크

$("username") 문법은 document.getElementById("username"); 을 의미함.

9장에서는 요청과 응답으로 데이터를 주고 받을 때 사용하는 방식에 대해 설명한다.

1. XML 2. JSON 3. innerHTML

 

# JSON 객체의 멤버에 접근하는 예제

for ( var property in hero ) {

alert("Found a property named : " + property);

}

 

# 예제소스 참조 XML 파싱

# 예제소스 참조 XML 파싱에서 어레이와 단순속성 파악후 처리.

# 예제소스 참조 JSON 파싱

# 예제소스 참조... property의 속성을 확인하여, 어레이와 단순속성을 확인하여 처리.

 

 

# 서버의 응답은 바로 실행하는 것보다는 분리해서 실행하는 것이 안전.

-> var itemDetails = JSON.parse(request.responseText);

JSON은 json2.js라 로드 될때 생성되며, parse는 문자열이 JSON형태면 객체를 반환.

 

# 예제소스 참조 안전한 방법 POST

registerRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

헤더 설정 필수, get 방식은 url전체를 보내는 것이라 설정할 필요가 없으나, post방식은 명시해줘야 함.

 

# 유명한 library ( framework)

1. script.acluo.us

2. yahoo ui (YUI)

3. prototype

4. jQuery

5. mooTools

Head+First+1장소스.js.js
0.00MB
Head+First+2장소스.js.js
0.01MB
util(Head+First).js.js
0.00MB

예전에는 JavaScript에 대해 다양한 기술이 난무하여 표준이 없었으나, 산업이 발전하다 보니 표준기술보다는 산업의 기술(구굴, 페이스북 등)에서 프레임워크로 Ajax보다 뛰어난 것들이 많이 나오고 있다. 모든 것은 기본이 충실하면 이해가 쉬우니 느리더라도 단계를 밟아 가길 바라며, 바쁘다면 열심히 읽기 바란다.

 

Posted by 목표를 가지고 달린다
,

금융권 종사자는 필수, 일부 행정관련 업무 관련 IT업무 담당자는 반드시 알아야 하는 검증식.

 

금융거래실명법에 의거하여, 금융거래는 "주민등록번호", "외국인등록번호", "여권조합번호"로 거래를 할 수 있다.

 

해당 실명번호가 맞는지를 IT담당자는 체크할 필요가 있어서 붙이며,

 

실제 실명번호에 130229-******* 등.. 잘못된 생년월일이나, 잘못된 체크디짓으로 부여된 번호가 있을 수도 있으므로,

어느정도로 적용할지를 반드시 이용자(기획자)와 협의 후....적용

 

예) 891230-1234560

주민등록번호를 2부터9까지 다시 2부터 5까지 올림차순으로 곱해서 더한다.

8x2+9x3+1x4+2x5+3x7+0x8+1x9+2x2+3x3+4x4+5x5=141

더한값을 11로 나눈다.(12.8)-소수첫째 자리까지 반올림

소수첫째자리 숫자에 10을 더해서 11이 되면 OK(외국인등록번호는 13)

소숫점 없이 11로 나누어 떨어져도 OK

 

내국인 주민등록번호 검증 엑셀 수식

=IF(RIGHT(C7,1)=(RIGHT(11-MOD(MID(C7,1,1)*2+MID(C7,2,1)*3+MID(C7,3,1)*4+MID(C7,4,1)*5+MID(C7,5,1)*6+MID(C7,6,1)*7+MID(C7,7,1)*8+MID(C7,8,1)*9+MID(C7,9,1)*2+MID(C7,10,1)*3+MID(C7,11,1)*4+MID(C7,12,1)*5,11),1)),"O","X")

 

외국인 등록번호 검증 엑셀 수식

=IF(RIGHT(C7,1)=(RIGHT(13-MOD(MID(C7,1,1)*2+MID(C7,2,1)*3+MID(C7,3,1)*4+MID(C7,4,1)*5+MID(C7,5,1)*6+MID(C7,6,1)*7+MID(C7,7,1)*8+MID(C7,8,1)*9+MID(C7,9,1)*2+MID(C7,10,1)*3+MID(C7,11,1)*4+MID(C7,12,1)*5,13),3)),"O","X")

 

Posted by 목표를 가지고 달린다
,