GULGUL CODING

230630 230703 본문

GULGUL/굴굴공부

230630 230703

OKKK굴 2023. 7. 7. 16:03

ORACLE DB 공부
*단축키 
한줄 복사: 워크시트의 커서가 있는 라인을 아래로 복사하는 단축키:
Ctrl + Shift + D
한줄 삭제: 워크시트의 커서가 있는 라인을 삭제하는 단축키:
Alt + Shift + D
alt + "'" : 대소문자 변경하기

[오라클 기초]
// https://www.youtube.com/watch?v=hCLdbM_bgrs 강좌


SQL -> DML (insert,select,update,delete) 
DBMS
DATABASE : 데이터를 모아서 쓰자, 중복을 솎아내고 결함을 없애는게 목적

1. 산술연산자
+; 숫자만 더함
|| : 문자열 덧셈
-일반적으로 숫자||문자는 되지않음
-ex) 이름(아이디) 출력 방법
select name||'('||ID||')' from member 
이런 연산자를 쓸때는 별칭을 작성하나 일반적으로 as를 생략한다.
select name||'('||ID||')' as Name from member
2.  비교연산자
=, !=, ^=,<>,>,<,>=,<=, IS NULL, IS NOT NULL
같지않다 != ^= <> 

select * from notice where writer_id='newlec';
select * from notice where HIT >3;
-null 값 찾을때 content='null'이 아닌 부분 주의. 
select * from notice where content IS NULL;

3.관계연산자
NOT, AND, OR, BETWEEN, IN
select * from notice where hit=0 or hit=2 or hit =7 이 쿼리를
select * from notice where hit in (0,2,7) 로 축약하여 작성할 수 있다.
select * from notice where hit not in (0,2,7) 반대되는 경우 not 위치 주의

4.패턴비교연산자
LIKE, % , _
-박 씨 성을 조회
select * from member where name ='박%'; (절대 안됨) 
select * from member where name like '박%';
-박씨이면서 이름이 외자인 회원
select * from member where name like '박_';  

select * from member where name not like '박%'
select * from member where name like '%도%';

5.정규식을 이용한 패턴연산(REGEXP_LIKE)
참고사이트: https://regexlib.com/?AspxAutoDetectCookieSupport=1 
select * from notice where title like '%-%-%';
--정규식을 사용하여 검색하는 경우  REGEXP_LIKE
select * from notice where REGEXP_LIKE(TITLE,'01[016-9]-\d{3,4}-\d{4}');
--[]는 숫자 하나가 들어갈수 있는 공간을 말함 [016789]라고 적으면 이자리에 0,1,6,7,8,9,중 하나가 올수있다는 의미.
--[...] 반복의 의미 
--[0-9] 0부터 9까지의 숫자 => 정규식으로 바꾸면 \d와 같다.
-- ^01[016-9]-\d{3,4}-\d{4}$ 
-- \d{3,4}: 조건이 3번반복이거나 4번반복이다.
-- ^시작과 $끝(이것이 포함된 문자를 찾을때는 빼야함)
--이메일 (\w: [a-zA-Z_0-9] \D: [^0-9] (첫자리의 숫자값이 오는것을 막는다) (org|net|com): org, net, com 중 하나만 들어오게 한다.
-- \D\w*@\D\w+.(org|net|com) 

6.rownum 그리고 행 제한하기
--rownum은 결과집합을 만들때 생성되는것이기 때문에 항상 1부터 시작한다.
select * from notice where rownum between 1 and 3;
select * from notice where rownum between 2 and 6; --실행안됨
--해결방법
select * from (select rownum num , notice.*from notice) where num between 1 and 3; 
--()안의 값은 새로운 가상의 테이블이라고 생각해야한다.
select * from (select rownum num , notice.*from notice) where num between 4 and 5;

--rownum은 where절 시작할때 작성되기 때문에 orderby시 순서가 엉망이 될 수있다.
--이경우, rownum() over (order by 정렬칼럼) 으로 넣어주면 잘 순서가 정렬됨.

7. 중복값 제거  distinct
select distinct age from member;
다중컬럼은 불가, 하나의 컬럼만 뽑아내어 중복제거


[함수]
1.문자열
-SUBSTR (문자열, 시작위치, 길이)
 SELECT SUBSTR('HELLO',1,3) FROM DUAL; => 1번째부터 3개문자 출력 => HEL
 SELECT SUBSTR('HELLO',3) FROM DUAL;=>3 번째 문자 출력 =>LLO
 SELECT SUBSTRB('HELLO',3) FROM DUAL; =>3 번재 바이트 부터 자른다.
 SELECT SUBSTRB('한글',3) FROM DUAL;=> 영문은 1바이트가 한글자이지만 영문외 다른문자는 3바이트이므로 => 글 만 출력
 사용예시) 모든 학생의 이름과 출생 월만을 조회하시오.
 SELECT NAME,SUBSTR(BIRTH,6,2) BIRTH_MONTH FROM MEMBER --생일데이터:2023-12-25 이런경우. 
 사용예시2) 회원중에 전화번호가 011로 시작하는 회원의 모든 정보를 출력하세요.
 SELECT * FROM MEMBER WHERE SUBSTR(PHONE,1,3)='010';
 사용예시3) 역해석
 SELECT first_name, SUBSTR(last_name, 1, 3) AS initials FROM employees;
 -> 회사원들의 성과 이름을 출력하는데 이름을 1번째부터 3단어를 끊어서 initials 라 명하고 출력한다.
 출력문 예시  예) 남궁 아무개일이삼
 firt_name | initials
 -------------------------
남궁   | 아무개
*단 여기서 함수가 where절에 호출되면 전체테이블의 1억개가 있다면 1억개를 다 조회하기 때문에 
연산자를 쓸수 있다면 연산자를 쓰는게 데이터 부하가 적다.

사용예시4) 전화번호를 등록하지 않은 사람들 중에서 생일이 7,8,9가 아닌 사람들을 조회하기
SELECT * FROM MEMBER WHERE SUBSTR(BIRTHDAY,6,2) NOT IN ('07','08','09') AND PHONE IS NULL;
-CONCAT('홍','길동')  : 보통은 문자열 연산자 || 을 더 많이 사용.
-TRIM('  HELLO   ') : 공백제거 
LTRIM , RTRIM : 각각 왼쪽, 오른쪽 공백제거를 의미
-LOWER('문자열') || UPPER('문자열') : 소문자 또는 대문자로 변경하기
일반적으로 대소문자 구분없이 검색 할때 사용.
SELECT LOWER('nERWEf') FROM DUAL;
SELECT UPPER('nERWEf') FROM DUAL;
-REPLACE (문자열, 찾는문자열, 대치할문자열) / TRANSLATE()
REPLACE : 문자구성이 바뀜
SELECT REPLACE('WHERE WE ARE','WE','YOU') FROM DUAL; => WHERE YOU ARE (WE가 YOU 로 변경)
TRANCELATE: 단어 하나하나가 바뀜
SELECT TRANSLATE('WHERE WE ARE','WE','YOU') FROM DUAL;=>YHORO YO ARO (W가 Y, E가 O로 변경)
사용예시1) 이름과 주소를 조회하세요 (단, 주소는 빈칸없이 조회)
SELECT NAME, REPLACE(ADDRESS,' ','') FROM STUDENTS
-문자열 패딩함수 (LPAD,RPAD)
SELECT LPAD('HELLO',5) FROM DUAL;
SELECT LPAD('HELLO',5,'0') FROM DUAL;=>HELLO
SELECT LPAD('HELLO',10,'0') FROM DUAL; =>00000HELLO
SELECT RPAD('HELLO',10,'0') FROM DUAL; =>HELLO00000
사용예시) 회원의이름을 조회하세요 (단, 이름의 길이가 3자가 안되는 경우는 이름 오른쪽을 밑줄_로 채우세요)
SELECT RPAD(NAME,6,'_') FROM MEMBER; 
*주의)일반적으로 바이트를 기준으로 두기 때문에 한글을 사용하는경우 3바이트 1글자에 조심하여 바이트값을 작성한다.
-INITCAP : 앞글자를 대문자나 소문자로 변경하기
SELECT INITCAP('the important thing is..') FROM DUAL;
=>The Important Thing Is..
*주의
SELECT INITCAP('the imp한글ortant t한글hing i@s..') FROM DUAL;
=>The Imp한글Ortant T한글Hing I@S.. 출력.
-INSTR (문자열, 검색문자열, 찾기시작하는 위치, 몇번째위치를 찾아야하는지)
SELECT INSTR('ALL WE NEED TO IS JUST TO..','TO') FROM DUAL =>13 (13번째 위치에 있다/띄어쓰기 포함.)
SELECT INSTR('ALL WE NEED TO IS JUST TO..','TO',15) FROM DUAL =>24 15번째 이후부터 검색했을때 24번째 위치에 있다.
SELECT INSTR('ALL WE NEED TO IS JUST TO..','TO',1,2) FROM DUAL =>24 1번째부터 2번째 TO 가 몇번째인지.
사용예시) 회원의 첫번째 - 문자와 두번째 - 문자 사이의 간격은?
SELECT INSTR(PHONE,'-',1,2)-INSTR(PHONE,'-',1,1)-1 간격 FROM MEMBER; 
사용예시) 전화번호 가운데 국번이 3자리 또는 4자리로 이뤄져있을때 국번만 추출
SELECT SUBSTR(PHONE, 5,INSTR(PHONE,'-',1,2)-INSTR(PHONE,'-',1,1)-1) FROM MEMBER;
2.숫자
3.날짜
4.변환
5.NULL
6.집계

-DECODE 함수 : DECODE 함수는 프로그래밍에서의  if else 와 비슷한 기능을 수행 
 DECODE(컬럼, 조건1, 결과1, 조건2, 결과2, 조건3, 결과3..........) 
사용예시)
SELECT DECODE(3,  1, 'ONE', 2, 'TWO', 3, 'THREE', 'NOT EXISTS')
FROM DUAL; =>THREE


[프로시저와 함수]
 https://www.youtube.com/watch?v=QqARY5PVNo4 강좌

1. 프로시저 (Procedure)
1)정의
-업무를 처리하기 위한 절차
-결과값 반환 없이 특정 로직을 처리
-질의의 집합으로 어떤 동작을 일괄 철
-테이블에서 데이터 추출 및 조작, 결과를 다른테이블에 저장하거나 갱신

2)프로시저 기본형
CREATE OR REPLACE PROCEDURE 프로시저 이름
( 매개변수 이름 1 [ IN | OUT | IN OUT ] 데이터 타입,
매개변수 이름 2 [ IN | OUT | IN OUT ] 데이터 타입, … )
IS | AS
변수 및 상수 선언
BEGIN
실행 문장
EXCEPTION 문장
END;
-in 입력 | out 출력 | in out 입출력 동시
-as 상수선언
begin 실행 exception 예외 (보통 if 문 대신사용)

3)프로시저 실행
둘중 하나로 사용.
EXECUTE 프로시저 이름();
EXEC 프로시저 이름();

4)변수의 종류
-일반변수: 변수명 타입(),
count NUMBER();
emp_name VARCHAR2(10);
-상수: 변수명 CONSTANT 타입();
count CONSTANT NUMBER();
emp_name CONSTANT VARCHAR2(10);

-%TYPE : 변수명 테이블명.테이블변수%TYPE (받아오는 테이블 변수의 타입을 모를때 사용하기 좋다)
테이블 열1개의 데이터 형식 접근
emp_name EMPLOYEES.EMPLOYEE_ID%TYPE
emp_email EMPLOYEES.EMAIL%TYPE

-%ROWTYPE : 변수명 테이블명%ROWTYPE
테이블 전체 열의 데이터 형식에 접근 ( 객체 받듯이 전체 타입을 다 받아옴)
emp EMPLOYEES%ROWTYPE
dept DEPARTMENTS%ROWTYPE

-RECORD : TYPE 사용자정의타입명 IS RECORD (변수 타입(),변수 타입(),...);
  변수 사용자정의타입명;
여러개의 열의 데이터 형식을 지정.  
TYPE user_type IS RECORD (name VARCHAR2(10), email VARCHAR2(20));
user user_type;
//RECORD  부분은 조금 더 찾아보기 💛

-COLLECTION : 배열과 유사하며 varray,중첩테이블, 연관배열 등이 있음.
TYPE v_array_type IS VARRAY(5) OF NUMBER(10);
v_array v_array_type; //타입지정, VARRAY(5) -5칸의 공간부여

TYPE nest_tbl_type IS TABLE OF VARCHAR2(10);
nest_tbl nest_tbl_type; //테이블 형태

TYPE a_array_type IS TABLE OF NUMBER(10) INDEX BY VARCHAR2(10);
a_array a_array_type; //INDEX가 정의되어있음. 키 = 값 구조로 되어있다.


2.프로시저활용
SET SERVEROUTPUT ON; 서버출력을 허용해야 작동함 (1회만 해주면 됨)
1) 기본 프로시저 작성 : 변수가 없는 경우 
CREATE OR REPLACE PROCEDURE first_emp 
AS 
emp_name VARCHAR2(20);
BEGIN
SELECT first_name || ' ' || last_name INTO emp_name
FROM employees WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE(emp_name);
END;
/*
 * 변수 지정이 없는 경우 프로시저명 뒤에 () 가 없다.
 */
--실행코드
EXECUTE first_emp();

2) 기본 프로시저 작성 : 변수가 있는 경우,
CREATE OR REPLACE PROCEDURE print_emp (
emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE
) AS
emp_name VARCHAR2(20);
BEGIN
SELECT first_name || ' ' || last_name INTO emp_name
FROM employees WHERE employee_id = emp_id;
DBMS_OUTPUT.PUT_LINE(emp_name);
END;

--실행코드
EXECUTE print_emp(100);


3) 새로운 변수를 추가하여 출력하는 경우
CREATE OR REPLACE PROCEDURE emp_avg_salary (
avg_salary OUT NUMBER
) AS
BEGIN
SELECT AVG(salary) INTO avg_salary
FROM employees;
END emp_avg_salary;

--실행코드 : 프로시저 작성은 기존과 동일하나 출력시 프로시저안에서 새롭게 생긴 변수의 타입을 지정하고 내보낸다.
DECLARE
avg_salary NUMBER;
BEGIN
emp_avg_salary(avg_salary);
DBMS_OUTPUT.PUT_LINE(avg_salary);
END;

4) IF-ELSE문 사용 프로시저.
CREATE OR REPLACE PROCEDURE if_salary (
salary IN NUMBER
) AS
avg_salary NUMBER;
BEGIN
SELECT AVG(salary) INTO avg_salary FROM employees;
IF salary >= avg_salary THEN
DBMS_OUTPUT.PUT_LINE('평균 이상');
ELSE
DBMS_OUTPUT.PUT_LINE('평균 미만');
END IF;
END;
--실행코드
EXECUTE if_salary(7000); =>평균이상 출력

/*
* else-if 는  
* IF 조건 THEN 
* 조건이 참인경우 실행문 
* ELSE  
* 그외조건인경우 실행문 
* END IF 
* 형식으로 작성한다.
*/

5) case 문 사용 프로시저. 
CREATE OR REPLACE PROCEDURE case_hire_date (
emp_email IN EMPLOYEES.EMAIL%TYPE
) AS
hire_year NCHAR(2);
text_msg VARCHAR2(20);
BEGIN
SELECT TO_CHAR(hire_date, 'YY') INTO hire_year
FROM employees
WHERE email = emp_email;
CASE
WHEN (hire_year = '01') THEN text_msg := '01년도에 입사';
WHEN (hire_year = '02') THEN text_msg := '02년도에 입사';
WHEN (hire_year = '03') THEN text_msg := '03년도에 입사';
WHEN (hire_year = '04') THEN text_msg := '04년도에 입사';
WHEN (hire_year = '05') THEN text_msg := '05년도에 입사';
WHEN (hire_year = '06') THEN text_msg := '06년도에 입사';
WHEN (hire_year = '07') THEN text_msg := '07년도에 입사';
WHEN (hire_year = '08') THEN text_msg := '08년도에 입사';
WHEN (hire_year = '09') THEN text_msg := '09년도에 입사';
ELSE text_msg := '01~09년도 이외에 입사';
END CASE;
DBMS_OUTPUT.PUT_LINE(text_msg);
END;
--실행코드
EXECUTE case_hire_date('SKING');

/*
*--TO_CHAR 함수를 이용해 데이터 형식을 바꿔줌.
*--CASE문
* CASE
* WHEN 조건 THEN 조건일때의 실행문;
* WHEN 조건 THEN 조건일때의 실행문;
* ...
* ELSE 
* END CASE;
*/

6) while문 사용 프로시저. (반복문)
CREATE OR REPLACE PROCEDURE while_print AS
str VARCHAR(100);
i NUMBER;
BEGIN
i := 1;
WHILE (i <= 10) LOOP
str := '반복 횟수:' || '(' || i || ')';
DBMS_OUTPUT.PUT_LINE(str);
i := i + 1;
END LOOP;
END;
--실행코드
EXECUTE while_print();

/*
* := 이게 ==의 개념인것 같다.
*--WHILE 문
* WHILE (조건) LOOP
* 반복문중 실행할 내용.
* END LOOP;
*/
-----------------------------------------------------------------------------------------------230703
7)  out 파라미터 프로시저 (+ 예외처리)
CREATE OR REPLACE PROCEDURE out_emp (
emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE,
out_str OUT VARCHAR2
) AS
emp_name VARCHAR2(20);
BEGIN
SELECT first_name || ' ' || last_name INTO emp_name
FROM employees WHERE employee_id = emp_id;
IF emp_id = NULL THEN
out_str := '직원: 없음';
ELSE
out_str := '직원: ' || emp_name;
END IF;
END;

--실행코드
DECLARE
out_str VARCHAR2(30);
BEGIN
out_emp(100, out_str);
DBMS_OUTPUT.PUT_LINE(out_str);
END;

/*
* 100이 아니라 DB에 없는 값인 300을 입력하면 
* 데이터에 값이 존재하지 않기 때문에 
* select 문 자체의 값이 없으므로 if 문이 실행되지 않아서 no_data가 발생.
*/

이 경우는 
CREATE OR REPLACE PROCEDURE out_emp(
emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE,
out_str OUT VARCHAR2
)AS
emp_name VARCHAR2(20);
BEGIN
SELECT first_name || ' ' || last_name INTO emp_name
FROM employees WHERE employee_id = emp_id;
out_str := '직원: ' || emp_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
out_str := '직원: 없음';
END;
으로 예외처리를 한다.

8) IN OUT 파라미터 사용 프로시저

CREATE OR REPLACE PROCEDURE in_out_emp(
    emp_name IN OUT VARCHAR2
)AS
BEGIN
SELECT first_name || ' ' || last_name INTO emp_name
FROM employees
WHERE first_name = emp_name OR last_name = emp_name;

emp_name := '직원: ' || emp_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
emp_name := '직원: 없음';
END;

--실행코드
DECLARE
emp_name VARCHAR2(30) := 'Lisa';
BEGIN
in_out_emp(emp_name);
DBMS_OUTPUT.PUT_LINE(emp_name);
END;

9)rowtype 사용 프로시저
CREATE OR REPLACE PROCEDURE rowtype_emp(
emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE
)AS
emp_row EMPLOYEES%ROWTYPE; --EMPLOYEES 테이블의 모든 rowtype을 가져온다.
BEGIN
SELECT first_name, last_name, job_id
INTO emp_row.first_name, emp_row.last_name, emp_row.job_id
FROM employees WHERE employee_id = emp_id;
DBMS_OUTPUT.PUT_LINE(emp_row.first_name || ' | ' ||
emp_row.last_name || ' | ' ||
emp_row.job_id);
END;
--실행코드
EXECUTE rowtype_emp(100);

10) RECODE 프로시저
CREATE OR REPLACE PROCEDURE record_emp(
emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE
)AS 
TYPE emp_type IS RECORD ( first_name VARCHAR2(10),
last_name VARCHAR2(10),
job_id VARCHAR(10));
   emp_record emp_type; --변수선언 오른쪽을 왼쪽으로 정의, 새로운 정의를 꼭 해줘야함.
BEGIN
SELECT first_name,last_name, job_id
INTO emp_record.first_name,emp_record.last_name,emp_record.job_id
FROM employees WHERE employee_id=emp_id;
DBMS_OUTPUT.PUT_LINE(emp_record.first_name || ' | ' ||
emp_record.last_name || ' | ' ||
emp_record.job_id);
END; 
--실행코드
EXECUTE rowtype_emp(100);

11) collection 사용 프로시저
배열과 유사하며 varray, 중첩테이블(VARRAY와는 달리 동적으로 공간생성), 연관배열  세가지를 예시로 들어봄.

CREATE OR REPLACE PROCEDURE collection_ex 
AS
TYPE v_array_type IS VARRAY(5) OF NUMBER(10); --5개의 공간이 있는 NUMBER 타입 배열 생성
TYPE nest_tbl_type IS TABLE OF VARCHAR2(10); --중첩테이블 생성
TYPE a_array_type IS TABLE OF NUMBER(10) INDEX BY VARCHAR2(10); --연관배열( KEY VALUE 구조)
v_array  v_array_type;
nest_tbl nest_tbl_type;
a_array a_array_type;
idx VARCHAR2(10);
BEGIN
v_array := v_array_type(1,2,3,4,5);
nest_tbl := nest_tbl_type('A', 'B', 'C', 'D', 'E');

--'A'라는 인덱스의 값 1을 의미
a_array('A') := 1;
a_array('B') := 2;
a_array('C') := 3;
a_array('D') := 4;
a_array('E') := 5;

--v_array와 nest_tbl을 반복문으로 모두 출력.
FOR i IN 1 .. 5 LOOP
DBMS_OUTPUT.PUT_LINE(v_array(i) || ' | ' || nest_tbl(i)); --1 | A
END LOOP;

--a_array 출력
idx := a_array.FIRST;
WHILE idx IS NOT NULL LOOP --인덱스가 NULL이 아닐때 까지 반복
DBMS_OUTPUT.PUT_LINE(idx || ' : ' || a_array(idx)); --'A':1 이런식으로 출력.
idx := a_array.NEXT(idx); --인덱스를 더해가면서.
END LOOP;
END;

--실행코드
EXECUTE collection_ex();

--테이블 부분 부가설명
중첩 테이블은 크기에 제한이 없다는 점은 연관 배열과 같지만, 
숫자형 인덱스만 사용할 수 있고 생성자를 사용하며 일반 테이블의 컬럼 타입으로 사용될 수 있다는 점은 VARRAY와 같다. 
중첩 테이블의 선언 방식은 다음과 같다.
    TYPE 중첩_테이블명 IS TABLE OF 값타입 ;

[커서]

1.정의 
프로시저내에서 커서를 사용시, 일반 프로그래밍에서 파일처리하는것과 유사하게 반응시킬수 있다.
행의 집합을 다룰수 있는 편리한 기능 제공
테이블에서 여러개의 행을 질의 후 질의 결과인 행 집합을 한 행씩 처리
프로시저 내부에서 커서 사용.

2. 커서 처리 순서
1)커서선언 
CURSOR  커서 이름
2)커서 열기
OPEN 커서 이름
3)커서에서 데이터 가져오기 
FETCH
4)데이터 처리
5)커서닫기
CLOSE 커서 이름
/*
* 데이터 처리시 3,4번 반복을 통해 데이터를 처리한다.
*/

3. 커서를 사용하는 프로시저의 예
CREATE OR REPLACE PROCEDURE cursor_salary AS
sal NUMBER :=0 ;
cnt NUMBER :=0 ;
total NUMBER :=0 ;
CURSOR emp_cursor IS (SELECT salary FROM employees); --커서 선언
BEGIN
OPEN emp_cursor; --커서 열기
LOOP
FETCH emp_cursor INTO sal;  --커서에서 데이터 가져오기. (SAL에 커서에서 지정했던 데이터를 넣으세요)
EXIT WHEN emp_cursor%NOTFOUND; --아무값도 없을때는 그냥 그 부분을 빠져나가라.
total := total + sal;
cnt := cnt + 1;
END LOOP;
CLOSE emp_cursor;
DBMS_OUTPUT.PUT_LINE('평균 SALARY: ' || (total / cnt));
END;
 --실행구문
  EXECUTE cursor_salary(); 
  

[함수]   
1.함수의 정의
-프로시저의 각 프로세스를 수행하기 위해 필요한 기능
-일반적인 프로그래밍 언어에서 사용되는 함수처럼 복잡한 프로그래밍도 지원
2. 문법
CREATE OR REPLACE FUNCTION 함수 이름
( 매개변수 이름 1 데이터 타입,
매개변수 이름 2 데이터 타입, … )--in out은 없다.
RETURN 데이터 타입
IS | AS
변수 및 상수 선언
BEGIN
실행 문장
RETURN 반환값
EXCEPTION 문장
END;

3. 프로시저와 함수의 차이.
[[프로시저]]  [[함수]]
• 특정 작업 수행  • 특정 계산 수행
• 리턴값이 없을수도 있음   • 리턴값이 반드시 존재해야 함
• 리턴값을 여러개 가질 수 있음  • 리턴값을 하나만 가질 수 있음
• 서버(DB)에서 기술  • 클라이언트에서 기술
• 수식내에서 사용 불가  • 수식내에서만 사용 가능 --큰 차이.
• 단독으로 문장 구성 가능  • 단독으로 문장 구성 불가

4. 함수 예시
(년도를 반환하는 함수 | 나이를 계산하는 함수)
CREATE OR REPLACE FUNCTION to_yyyymmdd(date Date)
RETURN VARCHAR2
IS
char_date VARCHAR2(20);
BEGIN
char_date := TO_CHAR(date,'YYYYMMDD');
RETURN char_date;
END;    

--excute로 실행불가하므로 질의를 통해서 호출
SELECT to_yyyymmdd(SYSDATE) FROM dual;

CREATE OR REPLACE FUNCTION get_age(date Date)
RETURN NUMBER
IS
age NUMBER;
BEGIN
age := TRUNC(MONTHS_BETWEEN(TRUNC(SYSDATE),to_yyyymmdd(date))/12);
--MONTHS_BETWEEN('날짜1','날짜2') == 날짜1-날짜2==개월 수 
RETURN age;
END;

--excute로 실행불가하므로 질의를 통해서 호출 아까 쓴 함수도 사용했음.
SELECT get_age('19901128') FROM dual;

5. 테이블 타입 정의 및 반환 함수
1) 만들 테이블의 타입정의
CREATE OR REPLACE TYPE ename_type AS OBJECT
(
f_name VARCHAR2(20),
l_name VARCHAR2(20)
);

2) 테이블 타입정의
CREATE OR REPLACE TYPE ename_table AS TABLE OF ename_type;

3) 테이블 반환함수
CREATE OR REPLACE FUNCTION emp_table (emp_id NUMBER)
RETURN ename_table
PIPELINED --꼭 써줘야 함.
IS
ename ename_type;
BEGIN
FOR emp IN (SELECT first_name,last_name FROM employees WHERE employee_id=emp_id)
LOOP
ename:= ename_type(emp.first_name, emp.last_name);
PIPE ROW(ename); --꼭 써줘야 함.
END LOOP;
RETURN;
END;

4) 실행
SELECT * FROM TABLE(emp_table(100));




--예시연습1

CREATE OR REPLACE PROCEDURE if_minmax_salary(
    salary IN NUMBER
)AS
avg_min_salary NUMBER;
avg_max_salary NUMBER;
BEGIN
SELECT AVG(min_salary), AVG(max_salary)
INTO avg_min_salary, avg_max_salary
FROM jobs;

IF salary <= avg_min_salary THEN 
DBMS_OUTPUT.PUT_LINE('최저 평균 이하');
ELSIF salary >= avg_max_salary THEN 
DBMS_OUTPUT.PUT_LINE('최대 평균 이상');
ELSE 
DBMS_OUTPUT.PUT_LINE('평균 구간');
END IF;    
END;

EXECUTE if_minmax_salary(19000);

--예시연습2
CREATE OR REPLACE PROCEDURE gugudan AS
str VARCHAR2(100);
i NUMBER;
k NUMBER;
BEGIN
i :=2;
WHILE (i<10) LOOP
str :=' ';
k :=1;
WHILE (k<10) LOOP
 str := str ||' '||i||'x'||k|| '='||i*k;
 k:= k+1;
END LOOP;
DBMS_OUTPUT.put_line(str);
i:= i+1;
   END LOOP ;
END;

execute gugudan();

--예시연습3
CREATE OR REPLACE PROCEDURE cursor_it_prog AS
fname VARCHAR2(20);
lname VARCHAR2(20);
jobid VARCHAR2(20);
CURSOR emp_cursor IS
SELECT first_name,last_name,job_id FROM employees;
BEGIN
DBMS_OUTPUT.PUT_LINE('[IT Programmer]');
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO fname, lname, jobid;
EXIT WHEN emp_cursor%notfound;
IF jobid='IT_PROG' THEN
   DBMS_OUTPUT.PUT_LINE(fname||' '||lname);
END IF;
END LOOP;
CLOSE emp_cursor;
END;

execute  cursor_it_prog ();

--예시연습4
create or replace type job_salary_type as object
(
   job_title varchar2(50),
   avg_salary number
);

create or replace type job_salary_table_type as table of job_salary_type;

--job_title마다 평균 salary를 내림차순으로 출력하는 테이블 반환 함수정의

CREATE OR REPLACE FUNCTION job_salary_table
RETURN job_salary_table_type
PIPELINED
IS
job_salary job_salary_type;
BEGIN 
--salary 값은 employees 에 있음.
FOR JOB IN (
SELECT jobs.job_title job_title, AVG(salary) avg_salary
FROM employees, jobs
WHERE employees.job_id = jobs.job_id
GROUP BY jobs.job_title
ORDER BY AVG(salary) DESC
)
LOOP
   job_salary :=job_salary_type(job.job_title, job.avg_salary);
   PIPE ROW(job_salary);
END LOOP;

RETURN;
END;

select * from (job_salary_table());  

[데이터 분석]

--https://www.data.go.kr/ 공공데이터 사이트
새로운 아이디 만들어서 csv 파일 다운후 로컬로 임폴트.

select * from commerce;

select distinct 상권_구분_코드_명 from commerce;
select distinct 서비스_업종_코드_명 from commerce;

select 상권_구분_코드_명,sum(점포수) from commerce group by 상권_구분_코드_명;
select 서비스_업종_코드_명,sum(주중_매출_금액),sum(주말_매출_금액) from commerce group by 서비스_업종_코드_명;
select 서비스_업종_코드_명,
sum(월요일_매출_금액),sum(화요일_매출_금액),sum(수요일_매출_금액),
sum(목요일_매출_금액),sum(금요일_매출_금액) 
from commerce 
group by 서비스_업종_코드_명;

select 서비스_업종_코드_명,
avg(월요일_매출_금액),avg(화요일_매출_금액),avg(수요일_매출_금액),
avg(목요일_매출_금액),avg(금요일_매출_금액) 
from commerce 
group by 서비스_업종_코드_명;


select 서비스_업종_코드_명,
avg(남성_매출_금액),avg(여성_매출_금액)
from commerce 
group by 서비스_업종_코드_명;

select 서비스_업종_코드_명,
avg(연령대_10_매출_금액),avg(연령대_20_매출_금액),avg(연령대_30_매출_금액),
avg(연령대_40_매출_금액),avg(연령대_60_이상_매출_금액) 
from commerce 
group by 서비스_업종_코드_명;

[테이블 owner 조회]
 모든 테이블 중에서 해당 테이블명을 가진 소유자를 검색.
SELECT table_name, owner
FROM all_tables
WHERE table_name = '테이블명';

[인덱스 생성- B-트리 인덱스]
오라클을 다양한 종류의 인덱스를 생성해서 사용할수 있다.
B-트리 인덱스, 비트맵 인덱스, 파티션 인덱스 등등..
가장 많이 사용하는 B-트리 인덱스에 대한것만 적어보겠다.

1.기본형
CREATE [UNIQUE] INDEX [스키마명.]인덱스명
ON [스키마명.]테이블명 (컬럼1 [, 컬럼2, 컬럼3, ...])
대괄호([]) 항목은 생략이 가능하다. 
인덱스는 한 개 이상의 컬럼으로 만들 수 있으며, 
하나의 테이블에 여러 개의 인덱스를 생성할 수 있다. 
테이블에 인덱스가 많이 생성되어 있으면, 
SELECT는 빠를 수 있지만 데이터 변경(INSERT, UPDATE, DELETE)은 느려질 수 있으므로 주의

2.단일형
CREATE INDEX 인덱스이름 ON 테이블명( 인덱스로 지정할 테이블 열 ASC 또는 DESC 를 붙여줄수있음.);
ex)
CREATE INDEX emp_ix01 ON emp(hiredate) --정렬에 관하여 아무것도 적지 않으면 오름차순 Default
CREATE INDEX emp_ix01 ON emp(hiredate DESC) 

3.복수형
CREATE INDEX emp_ix02 ON emp(job, deptno)


[테이블에서 INSERT 하는 법]
테이블 1에 테이블2의 값을 등록할때 사용 (양이 많은경우)
INSERT INTO 테이블1
( 테이블1 열, 열 , 열,...
)
SELECT  테이블2 열, 열, 열 ,...
FROM 테이블2
WHERE 조건

--예시코드
INSERT INTO countries
( country_id,country_name,region_id
)
SELECT  country_id,country_name,region_id
FROM countries2

[SVN 사용]
 1. 정의
 -형상관리 소프트웨어
 -버젼관리 소프트웨어
 
 2. 세팅
1. visualsvn.com :: 저장소 제공하는것 같은데..좀더 찾아봐야겠다.(이전에는 구글을 사용한것 같다)
2. tortoisesvn.net :: GUI 형식으로 간편하게 SVN을 확인할수있다.
 3. SVN 용어
Repository : 저장소 , 서버에 올라가있는 저장소로 URL이 있는 모든 사용자가 접근가능
Revision : 리비전, 저장소에 올라가 있는 파일들의 버전이라고 생각하면 된다. 
이 리비전을 통해 롤백을 하거나 이전에 소스코드를 확인할 수 있다.
이 리비전 숫자는 commit 행위를 할 때마다 올라가게 되므로
커밋 시 어떤 변경사항들이 발생했는지 Commit Message 를 잘 작성해야 한다.
Trunk : 트렁크, 저장소의 중심.
Branch : 나뭇가지 (몸통에서==여기선 트렁크에서  파생되어나옴.)
branch를 만들어 개발하고 trunk에서 합치는 방향으로 개발 진행
Tag : 태그, 브랜치들이 모여서 만들어진 트렁크에 대해 어느 특정지점을 기록하기 위한  꼬리표.
Checkout : 체크아웃 체크아웃은 초기에 원격 저장소에서 작업을 하기 위해 소스코드를 내 PC 로 내려받는 것을 의미
git 의 clone과 유사
Commit : 커밋, 변경사항 저장,커밋을 하게 되면 저자(Author)와 커밋 메시지, 일자와 일시가 찍히고 리비전이 갱신

Merge : 머지, 병합
머지는 내 브랜치와 다른 사람이 작업해 둔 브랜치를 합치는 작업이다. 
업데이트 시에는 자동적으로 진행되는 작업이다
만약 충돌(Conflict)이 나면 리비전이 다른 두개의 버젼의 파일이 생성되고 직접 머지충돌을 해결한다.
Update : 업데이트
업데이트는 원격 저장소에서 다른 사람에 의해 변경된 소스 코드를 내 PC 에 반영하는 작업.
업데이트는 수시로 해주는 게 좋다. 작업을 시작하기 전에, 커밋을 하기 전에는 필수로 해준다.
Add : 추가, 원격 저장소에 커밋하기 위해 VCS(version control system:파일의 변화를 추적하고 관리하는 시스템)목록에 추가하는것.

230703 

7)  out 파라미터 프로시저 (+ 예외처리)
CREATE OR REPLACE PROCEDURE out_emp (
emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE,
out_str OUT VARCHAR2
) AS
emp_name VARCHAR2(20);
BEGIN
SELECT first_name || ' ' || last_name INTO emp_name
FROM employees WHERE employee_id = emp_id;
IF emp_id = NULL THEN
out_str := '직원: 없음';
ELSE
out_str := '직원: ' || emp_name;
END IF;
END;

--실행코드
DECLARE
out_str VARCHAR2(30);
BEGIN
out_emp(100, out_str);
DBMS_OUTPUT.PUT_LINE(out_str);
END;

/*
* 100이 아니라 DB에 없는 값인 300을 입력하면 
* 데이터에 값이 존재하지 않기 때문에 
* select 문 자체의 값이 없으므로 if 문이 실행되지 않아서 no_data가 발생.
*/

이 경우는 
CREATE OR REPLACE PROCEDURE out_emp(
emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE,
out_str OUT VARCHAR2
)AS
emp_name VARCHAR2(20);
BEGIN
SELECT first_name || ' ' || last_name INTO emp_name
FROM employees WHERE employee_id = emp_id;
out_str := '직원: ' || emp_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
out_str := '직원: 없음';
END;
으로 예외처리를 한다.

8) IN OUT 파라미터 사용 프로시저

CREATE OR REPLACE PROCEDURE in_out_emp(
    emp_name IN OUT VARCHAR2
)AS
BEGIN
SELECT first_name || ' ' || last_name INTO emp_name
FROM employees
WHERE first_name = emp_name OR last_name = emp_name;

emp_name := '직원: ' || emp_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
emp_name := '직원: 없음';
END;

--실행코드
DECLARE
emp_name VARCHAR2(30) := 'Lisa';
BEGIN
in_out_emp(emp_name);
DBMS_OUTPUT.PUT_LINE(emp_name);
END;

9)rowtype 사용 프로시저
CREATE OR REPLACE PROCEDURE rowtype_emp(
emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE
)AS
emp_row EMPLOYEES%ROWTYPE; --EMPLOYEES 테이블의 모든 rowtype을 가져온다.
BEGIN
SELECT first_name, last_name, job_id
INTO emp_row.first_name, emp_row.last_name, emp_row.job_id
FROM employees WHERE employee_id = emp_id;
DBMS_OUTPUT.PUT_LINE(emp_row.first_name || ' | ' ||
emp_row.last_name || ' | ' ||
emp_row.job_id);
END;
--실행코드
EXECUTE rowtype_emp(100);

10) RECODE 프로시저
CREATE OR REPLACE PROCEDURE record_emp(
emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE
)AS 
TYPE emp_type IS RECORD ( first_name VARCHAR2(10),
last_name VARCHAR2(10),
job_id VARCHAR(10));
   emp_record emp_type; --변수선언 오른쪽을 왼쪽으로 정의, 새로운 정의를 꼭 해줘야함.
BEGIN
SELECT first_name,last_name, job_id
INTO emp_record.first_name,emp_record.last_name,emp_record.job_id
FROM employees WHERE employee_id=emp_id;
DBMS_OUTPUT.PUT_LINE(emp_record.first_name || ' | ' ||
emp_record.last_name || ' | ' ||
emp_record.job_id);
END; 
--실행코드
EXECUTE rowtype_emp(100);

11) collection 사용 프로시저
배열과 유사하며 varray, 중첩테이블(VARRAY와는 달리 동적으로 공간생성), 연관배열  세가지를 예시로 들어봄.

CREATE OR REPLACE PROCEDURE collection_ex 
AS
TYPE v_array_type IS VARRAY(5) OF NUMBER(10); --5개의 공간이 있는 NUMBER 타입 배열 생성
TYPE nest_tbl_type IS TABLE OF VARCHAR2(10); --중첩테이블 생성
TYPE a_array_type IS TABLE OF NUMBER(10) INDEX BY VARCHAR2(10); --연관배열( KEY VALUE 구조)
v_array  v_array_type;
nest_tbl nest_tbl_type;
a_array a_array_type;
idx VARCHAR2(10);
BEGIN
v_array := v_array_type(1,2,3,4,5);
nest_tbl := nest_tbl_type('A', 'B', 'C', 'D', 'E');

--'A'라는 인덱스의 값 1을 의미
a_array('A') := 1;
a_array('B') := 2;
a_array('C') := 3;
a_array('D') := 4;
a_array('E') := 5;

--v_array와 nest_tbl을 반복문으로 모두 출력.
FOR i IN 1 .. 5 LOOP
DBMS_OUTPUT.PUT_LINE(v_array(i) || ' | ' || nest_tbl(i)); --1 | A
END LOOP;

--a_array 출력
idx := a_array.FIRST;
WHILE idx IS NOT NULL LOOP --인덱스가 NULL이 아닐때 까지 반복
DBMS_OUTPUT.PUT_LINE(idx || ' : ' || a_array(idx)); --'A':1 이런식으로 출력.
idx := a_array.NEXT(idx); --인덱스를 더해가면서.
END LOOP;
END;

--실행코드
EXECUTE collection_ex();

--테이블 부분 부가설명
중첩 테이블은 크기에 제한이 없다는 점은 연관 배열과 같지만, 
숫자형 인덱스만 사용할 수 있고 생성자를 사용하며 일반 테이블의 컬럼 타입으로 사용될 수 있다는 점은 VARRAY와 같다. 
중첩 테이블의 선언 방식은 다음과 같다.
    TYPE 중첩_테이블명 IS TABLE OF 값타입 ;

[커서]

1.정의 
프로시저내에서 커서를 사용시, 일반 프로그래밍에서 파일처리하는것과 유사하게 반응시킬수 있다.
행의 집합을 다룰수 있는 편리한 기능 제공
테이블에서 여러개의 행을 질의 후 질의 결과인 행 집합을 한 행씩 처리
프로시저 내부에서 커서 사용.

2. 커서 처리 순서
1)커서선언 
CURSOR  커서 이름
2)커서 열기
OPEN 커서 이름
3)커서에서 데이터 가져오기 
FETCH
4)데이터 처리
5)커서닫기
CLOSE 커서 이름
/*
* 데이터 처리시 3,4번 반복을 통해 데이터를 처리한다.
*/

3. 커서를 사용하는 프로시저의 예
CREATE OR REPLACE PROCEDURE cursor_salary AS
sal NUMBER :=0 ;
cnt NUMBER :=0 ;
total NUMBER :=0 ;
CURSOR emp_cursor IS (SELECT salary FROM employees); --커서 선언
BEGIN
OPEN emp_cursor; --커서 열기
LOOP
FETCH emp_cursor INTO sal;  --커서에서 데이터 가져오기. (SAL에 커서에서 지정했던 데이터를 넣으세요)
EXIT WHEN emp_cursor%NOTFOUND; --아무값도 없을때는 그냥 그 부분을 빠져나가라.
total := total + sal;
cnt := cnt + 1;
END LOOP;
CLOSE emp_cursor;
DBMS_OUTPUT.PUT_LINE('평균 SALARY: ' || (total / cnt));
END;
 --실행구문
  EXECUTE cursor_salary(); 
  

[함수]   
1.함수의 정의
-프로시저의 각 프로세스를 수행하기 위해 필요한 기능
-일반적인 프로그래밍 언어에서 사용되는 함수처럼 복잡한 프로그래밍도 지원
2. 문법
CREATE OR REPLACE FUNCTION 함수 이름
( 매개변수 이름 1 데이터 타입,
매개변수 이름 2 데이터 타입, … )--in out은 없다.
RETURN 데이터 타입
IS | AS
변수 및 상수 선언
BEGIN
실행 문장
RETURN 반환값
EXCEPTION 문장
END;

3. 프로시저와 함수의 차이.
[[프로시저]]  [[함수]]
• 특정 작업 수행  • 특정 계산 수행
• 리턴값이 없을수도 있음   • 리턴값이 반드시 존재해야 함
• 리턴값을 여러개 가질 수 있음  • 리턴값을 하나만 가질 수 있음
• 서버(DB)에서 기술  • 클라이언트에서 기술
• 수식내에서 사용 불가  • 수식내에서만 사용 가능 --큰 차이.
• 단독으로 문장 구성 가능  • 단독으로 문장 구성 불가

4. 함수 예시
(년도를 반환하는 함수 | 나이를 계산하는 함수)
CREATE OR REPLACE FUNCTION to_yyyymmdd(date Date)
RETURN VARCHAR2
IS
char_date VARCHAR2(20);
BEGIN
char_date := TO_CHAR(date,'YYYYMMDD');
RETURN char_date;
END;    

--excute로 실행불가하므로 질의를 통해서 호출
SELECT to_yyyymmdd(SYSDATE) FROM dual;

CREATE OR REPLACE FUNCTION get_age(date Date)
RETURN NUMBER
IS
age NUMBER;
BEGIN
age := TRUNC(MONTHS_BETWEEN(TRUNC(SYSDATE),to_yyyymmdd(date))/12);
--MONTHS_BETWEEN('날짜1','날짜2') == 날짜1-날짜2==개월 수 
RETURN age;
END;

--excute로 실행불가하므로 질의를 통해서 호출 아까 쓴 함수도 사용했음.
SELECT get_age('19901128') FROM dual;

5. 테이블 타입 정의 및 반환 함수
1) 만들 테이블의 타입정의
CREATE OR REPLACE TYPE ename_type AS OBJECT
(
f_name VARCHAR2(20),
l_name VARCHAR2(20)
);

2) 테이블 타입정의
CREATE OR REPLACE TYPE ename_table AS TABLE OF ename_type;

3) 테이블 반환함수
CREATE OR REPLACE FUNCTION emp_table (emp_id NUMBER)
RETURN ename_table
PIPELINED --꼭 써줘야 함.
IS
ename ename_type;
BEGIN
FOR emp IN (SELECT first_name,last_name FROM employees WHERE employee_id=emp_id)
LOOP
ename:= ename_type(emp.first_name, emp.last_name);
PIPE ROW(ename); --꼭 써줘야 함.
END LOOP;
RETURN;
END;

4) 실행
SELECT * FROM TABLE(emp_table(100));




--예시연습1

CREATE OR REPLACE PROCEDURE if_minmax_salary(
    salary IN NUMBER
)AS
avg_min_salary NUMBER;
avg_max_salary NUMBER;
BEGIN
SELECT AVG(min_salary), AVG(max_salary)
INTO avg_min_salary, avg_max_salary
FROM jobs;

IF salary <= avg_min_salary THEN 
DBMS_OUTPUT.PUT_LINE('최저 평균 이하');
ELSIF salary >= avg_max_salary THEN 
DBMS_OUTPUT.PUT_LINE('최대 평균 이상');
ELSE 
DBMS_OUTPUT.PUT_LINE('평균 구간');
END IF;    
END;

EXECUTE if_minmax_salary(19000);

--예시연습2
CREATE OR REPLACE PROCEDURE gugudan AS
str VARCHAR2(100);
i NUMBER;
k NUMBER;
BEGIN
i :=2;
WHILE (i<10) LOOP
str :=' ';
k :=1;
WHILE (k<10) LOOP
 str := str ||' '||i||'x'||k|| '='||i*k;
 k:= k+1;
END LOOP;
DBMS_OUTPUT.put_line(str);
i:= i+1;
   END LOOP ;
END;

execute gugudan();

--예시연습3
CREATE OR REPLACE PROCEDURE cursor_it_prog AS
fname VARCHAR2(20);
lname VARCHAR2(20);
jobid VARCHAR2(20);
CURSOR emp_cursor IS
SELECT first_name,last_name,job_id FROM employees;
BEGIN
DBMS_OUTPUT.PUT_LINE('[IT Programmer]');
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO fname, lname, jobid;
EXIT WHEN emp_cursor%notfound;
IF jobid='IT_PROG' THEN
   DBMS_OUTPUT.PUT_LINE(fname||' '||lname);
END IF;
END LOOP;
CLOSE emp_cursor;
END;

execute  cursor_it_prog ();

--예시연습4
create or replace type job_salary_type as object
(
   job_title varchar2(50),
   avg_salary number
);

create or replace type job_salary_table_type as table of job_salary_type;

--job_title마다 평균 salary를 내림차순으로 출력하는 테이블 반환 함수정의

CREATE OR REPLACE FUNCTION job_salary_table
RETURN job_salary_table_type
PIPELINED
IS
job_salary job_salary_type;
BEGIN 
--salary 값은 employees 에 있음.
FOR JOB IN (
SELECT jobs.job_title job_title, AVG(salary) avg_salary
FROM employees, jobs
WHERE employees.job_id = jobs.job_id
GROUP BY jobs.job_title
ORDER BY AVG(salary) DESC
)
LOOP
   job_salary :=job_salary_type(job.job_title, job.avg_salary);
   PIPE ROW(job_salary);
END LOOP;

RETURN;
END;

select * from (job_salary_table());  

[데이터 분석]

--https://www.data.go.kr/ 공공데이터 사이트
새로운 아이디 만들어서 csv 파일 다운후 로컬로 임폴트.

select * from commerce;

select distinct 상권_구분_코드_명 from commerce;
select distinct 서비스_업종_코드_명 from commerce;

select 상권_구분_코드_명,sum(점포수) from commerce group by 상권_구분_코드_명;
select 서비스_업종_코드_명,sum(주중_매출_금액),sum(주말_매출_금액) from commerce group by 서비스_업종_코드_명;
select 서비스_업종_코드_명,
sum(월요일_매출_금액),sum(화요일_매출_금액),sum(수요일_매출_금액),
sum(목요일_매출_금액),sum(금요일_매출_금액) 
from commerce 
group by 서비스_업종_코드_명;

select 서비스_업종_코드_명,
avg(월요일_매출_금액),avg(화요일_매출_금액),avg(수요일_매출_금액),
avg(목요일_매출_금액),avg(금요일_매출_금액) 
from commerce 
group by 서비스_업종_코드_명;


select 서비스_업종_코드_명,
avg(남성_매출_금액),avg(여성_매출_금액)
from commerce 
group by 서비스_업종_코드_명;

select 서비스_업종_코드_명,
avg(연령대_10_매출_금액),avg(연령대_20_매출_금액),avg(연령대_30_매출_금액),
avg(연령대_40_매출_금액),avg(연령대_60_이상_매출_금액) 
from commerce 
group by 서비스_업종_코드_명;

[테이블 owner 조회]
 모든 테이블 중에서 해당 테이블명을 가진 소유자를 검색.
SELECT table_name, owner
FROM all_tables
WHERE table_name = '테이블명';

[인덱스 생성- B-트리 인덱스]
오라클을 다양한 종류의 인덱스를 생성해서 사용할수 있다.
B-트리 인덱스, 비트맵 인덱스, 파티션 인덱스 등등..
가장 많이 사용하는 B-트리 인덱스에 대한것만 적어보겠다.

1.기본형
CREATE [UNIQUE] INDEX [스키마명.]인덱스명
ON [스키마명.]테이블명 (컬럼1 [, 컬럼2, 컬럼3, ...])
대괄호([]) 항목은 생략이 가능하다. 
인덱스는 한 개 이상의 컬럼으로 만들 수 있으며, 
하나의 테이블에 여러 개의 인덱스를 생성할 수 있다. 
테이블에 인덱스가 많이 생성되어 있으면, 
SELECT는 빠를 수 있지만 데이터 변경(INSERT, UPDATE, DELETE)은 느려질 수 있으므로 주의

2.단일형
CREATE INDEX 인덱스이름 ON 테이블명( 인덱스로 지정할 테이블 열 ASC 또는 DESC 를 붙여줄수있음.);
ex)
CREATE INDEX emp_ix01 ON emp(hiredate) --정렬에 관하여 아무것도 적지 않으면 오름차순 Default
CREATE INDEX emp_ix01 ON emp(hiredate DESC) 

3.복수형
CREATE INDEX emp_ix02 ON emp(job, deptno)


[테이블에서 INSERT 하는 법]
테이블 1에 테이블2의 값을 등록할때 사용 (양이 많은경우)
INSERT INTO 테이블1
( 테이블1 열, 열 , 열,...
)
SELECT  테이블2 열, 열, 열 ,...
FROM 테이블2
WHERE 조건

--예시코드
INSERT INTO countries
( country_id,country_name,region_id
)
SELECT  country_id,country_name,region_id
FROM countries2

[SVN 사용]
 1. 정의
 -형상관리 소프트웨어
 -버젼관리 소프트웨어
 
 2. 세팅
1. visualsvn.com :: 저장소 제공하는것 같은데..좀더 찾아봐야겠다.(이전에는 구글을 사용한것 같다)
2. tortoisesvn.net :: GUI 형식으로 간편하게 SVN을 확인할수있다.
 3. SVN 용어
Repository : 저장소 , 서버에 올라가있는 저장소로 URL이 있는 모든 사용자가 접근가능
Revision : 리비전, 저장소에 올라가 있는 파일들의 버전이라고 생각하면 된다. 
이 리비전을 통해 롤백을 하거나 이전에 소스코드를 확인할 수 있다.
이 리비전 숫자는 commit 행위를 할 때마다 올라가게 되므로
커밋 시 어떤 변경사항들이 발생했는지 Commit Message 를 잘 작성해야 한다.
Trunk : 트렁크, 저장소의 중심.
Branch : 나뭇가지 (몸통에서==여기선 트렁크에서  파생되어나옴.)
branch를 만들어 개발하고 trunk에서 합치는 방향으로 개발 진행
Tag : 태그, 브랜치들이 모여서 만들어진 트렁크에 대해 어느 특정지점을 기록하기 위한  꼬리표.
Checkout : 체크아웃 체크아웃은 초기에 원격 저장소에서 작업을 하기 위해 소스코드를 내 PC 로 내려받는 것을 의미
git 의 clone과 유사
Commit : 커밋, 변경사항 저장,커밋을 하게 되면 저자(Author)와 커밋 메시지, 일자와 일시가 찍히고 리비전이 갱신

Merge : 머지, 병합
머지는 내 브랜치와 다른 사람이 작업해 둔 브랜치를 합치는 작업이다. 
업데이트 시에는 자동적으로 진행되는 작업이다
만약 충돌(Conflict)이 나면 리비전이 다른 두개의 버젼의 파일이 생성되고 직접 머지충돌을 해결한다.
Update : 업데이트
업데이트는 원격 저장소에서 다른 사람에 의해 변경된 소스 코드를 내 PC 에 반영하는 작업.
업데이트는 수시로 해주는 게 좋다. 작업을 시작하기 전에, 커밋을 하기 전에는 필수로 해준다.
Add : 추가, 원격 저장소에 커밋하기 위해 VCS(version control system:파일의 변화를 추적하고 관리하는 시스템)목록에 추가하는것.

 
 4. 작동용어.
저장소 생성 - svnadmin create 저장소명
저장소 확인 - svnlook info 저장소명
저장소에서 작업 복제 - svn checkout 저장소_URL
파일 추가 - svn add 파일명
변경 내용 커밋 - svn commit -m "커밋 메시지"
변경 내용 업데이트 - svn update
변경 내용 로그 확인 - svn log
다른 저장소에서 변경 내용 가져오기 - svn merge 저장소_URL
변경 내용 비교 - svn diff 파일명
파일 또는 디렉토리 삭제 - svn delete 파일명
파일 또는 디렉토리 이름 변경 - svn rename 현재_이름 새로운_이름
 
 -- 다음할것
 1.SVN 실제로 사용해보기
 2.ORACLE JOIN 다시 보기
 

'GULGUL > 굴굴공부' 카테고리의 다른 글

230706  (0) 2023.07.07
Comments