이번 post는 생활코딩의 Oracle DB 강의를 참고하여 작성된 post입니다. :)
-- 04 Milestone
/*
- 환경설치
- CRUD
- GROUPING
CRUD를 grouping해서 더 크게 결과물 만들기
- RUN
*/
-- 05.1 User와 Schema
/* Schema */
/*
우리가 하려는 것은 Oracle DB로 table에 data를 Write/Read 하는 것이다.
Table을 만들어야하는데, Schema에 대해 먼저 알아놓아야 한다.
Table을 만들다보면, 점점 많아질 것이다. 즉 프로젝트가 커지면, table의 갯수가 엄청 많아진다.
그러면, 이것들이 산재하지 않고 어떤 체계로 존재해야 한다. 즉 이러한 시스템에서는 directory가 필요해진다.
그렇다면, 'table이 많아진다면, 서로 연관된 table을 grouping하기 위한 체계가 필요'하다고 이해할 수 있다.
이 체계를 schema라고 한다.
- Shema 이해하기
Schema는, 연관된 table들을 grouping하는 directory같은 것이다. (directory인 것은 아니지만..)
개념적으로 정확히는, 'schemar란, schema에 속한 table을 설명하는 개념'이기도 하다.
일단 연관된 table들을 grouping한다고 이해해두자.
다음 chapter에서는 user를 생성하여 schema를 만드는 작업을 알아보자.
그러고나서 table을 생성하는 것에 대해 다뤄볼 것이다.
*/
/* User */
/*
Schema를 만들고 사용하기 위해서는, user개념을 이해해야한다. 왜냐하면, oracle db는 user와 관련하여 비용이 매우 비싸지기 때문이다.
DataBase는 여러 컴퓨터에서 접근하여 사용되고, 각각 사용자는 자신들이 관리하는 table에 접속해서 data를 처리할 수 있다.
그리고 user를 생성하면, 이 user에 속하는 schema가 만들어진다. 둘이 같은 개념은 아니지만,
이 schema를 관리하는 것은 user이므로, 두 개념을 함께 이해할 필요가 있다.
*/
/* Schema 요약 */
/*
- Schema는 서로 연관된 table을 grouping하는 일종의 directory같은 것이다.
- User를 생성하면, 그 user에 해당하는 schema가 생성된다.
- Schema의 본질적인 정의는, 해당 schema에 속하는 table을 정의하는 정보이다.
*/
-- 05.2 User를 생성하는 방법
sqlplus sys AS SYSDBA;
/*
User를 생성하려면, 관리자 권한으로써 가능
기본적인 사용자인 sys로 로그인하는데, sys AS SYSDBA로하면,
system의 데이터베이스 관리자로써 `sys`라는 user를 로그인한다는 것
Oracle SQL Reference
네모는 그대로 사용해야하는 부분
원형은 임의적으로 작성하는 부분
분기는 선택가능한 옵션
*/
CREATE USER myuser IDENTIFIED BY 1111; -- 그냥 해보니 에러가 발생했다. CDB, PDB때문이다. 구글링해보니 여러 해결법이 있다.
ALTER SESSION SET"_ORACLE_SCRIPT"=true;
/*
그리고 sqlplus를 exit한 후, 다시 login하기 위해 myuser로 시도해보니 login denied되었다.
왜냐하면, 생성된 user인 myuser에게 'db에 접근가능한 권한'이 필요한데, 현재는 아무 권한도 없기 때문이다.
다음 chapter에서는 user에게 권한을 부여하는 방법을 알아보자.
*/
-- 05.3 User에게 DB권한 부여하는 방법
sqlplus sys AS SYSDBA; -- 우선 sys AS SYSDBA로 login한다. (비밀번호 안치고 그냥 enter해도 login됨)
GRANT DBA TO myuser;
/*
GRANT 명령어를 사용한다.
권한부여를 하는 명령이다.
어떤 권한을 부여할지 oracle reference를 참고할 수 있다.
GRANT DBA는 DataBase Administrator의 abbreviation
DB에 대한 모든 관리권한을 의미한다.
이렇게하면, `myuser`라는 user에게, DB에 대한 모든 관리권한이 부여된다.
실무에서는 DB를 관리하는 user와, 이용하는 user를 이원화시켜 관리하는 것이 가장 이상적이다.
그리고 실무라면, myuser에게 모든 권한을 주기보다는, 필요한만큼인 최소한의 권한을 주는 것이 좋다.
아무튼 grant되고 다시 sqlplus 명령어로 myuser login을 시도하면 성공한다.
*/
-- 06.1 Table을 생성하는 방법
CREATE TABLE topic (
id NUMBER NOT NULL,
title VARCHAR2(50) NOT NULL,
description VARCHAR2(4000),
created DATE NOT NULL
);
/*
CREATE TABLE sql references oracle을 검색해보면, oracle 공식문서를 볼 수 있다.
syntax에 create_table을 도식과 같이 한다고 설명되어 있다. (공식문서 참고)
CREATE 하고 TABLE이라는 keyword를 쓰고, shcema를 직접 지정할 수도 있다.
만약 schema를 특정하지 않는다면, user_name과 동일한 이름의 schema를 사용한다.
그리고나서 table name을 적는다.
또 3가지 중 하나를 선택하는데, relational_table은 어떻게 사용하는지 그 밑에 작성되어 있다.
Relational properties를 지정할수도있고 안 할 수도 있다.
Relational_properties에 대한 사용설명을 또 살펴보자.
Column을 정의하는 옵션, 여러 다른 옵션이 있다. 우리는 column_definition을 사용해서 각각의 column을 정의할 것이다.
참고로 `.`은 구분자(seperator)로써 사용되는 것이다.
사실 이 공식문서만 보고하기는 힘들다.
일반적인 문법을 사용해보자.
CREATE TABLE ORACLE을 검색해서 이미 작성된 구문형식을 사용할 수도 있다.
*/
-- 06.2 table_name을 read하는 방법
-- 지정된 user의 모든 table_name을 read하는 방법
SELECT table_name FROM all_tables WHERE OWNER = 'myuser1';
-- login한 현재 user의 table_name을 read하는 방법
SELECT table_name FROM user_tables;
-- 07 Table에, row data를 추가하는 방법
INSERT INTO topic
(id,title,description,created)
VALUES
(1, 'Oracle', 'Oracle is ...', SYSDATE);
commit; -- NOTE : table에 data를 CRUD할 때는 반드시 commit을 명령
/*
본격적으로 Database를 CRUD하려면, 먼저 table에 data 생성이 필요하다.
이를 위해 INSERT라는 명령을 사용할 것이다.
Topic table에다가 row를 추가하고자한다고 가정해보자.
참고로 terminal에서 ;을 입력하지 않고, 그냥 enter치면 line breaking하면서 가독성을 확보할 수 있다.
INSERT INTO (table_name)
(id,title,description, created)
column으로 id ,... 를 지정했다. 이 지정된 column에, insert되는 row data인 value가 입력된다.
VALUES
Input시킬 대상은 value이므로, VALUES라고 했다.
그리고 id의 value로 1, title로 'oracle', description에 'Oracle Is ..." 과 같은 data를 저장하려고 한다.
SYSDATE를 사용하면 created time을 알 수 있다.
이렇게 하고 실행하면, 행이 1개 추가되었다.
추가하고자하는 data를 table에 input하고나서는 반드시 commit; 명령을 해야 한다.
Transaction 섹션에서 commit에 대해 더 알아둘 것이 있는데, 일단 여기서는 commit이라는 명령어가 필수적이라고 알아두자.
`commit;`이 왜 필요한지 추후 알게될 것이다.
이제 실제 row에 데이터가 추가되었다.
*/
-- 08 SQL의 의미
/*
Database로 분류되는 시스템은, 스프레드시트같은 프로그램보다 data를 처리하는데 훨씬 효율적이고 빠르다.
Database는 instruction으로 db를 control할 수 있는 장점이 있다.
이 장점은 db시스템에서 data가 자동으로 처리될 수 있다는 매우 큰 장점으로 작용한다.
명령어를 이용해서 db를 제어할 수 있는데 이 명령어들을 SQL(Structured Query Language)이다.
구조화된 정보를 처리하도록 요청하는 언어라고 번역할 수 있다.
DBMS의 절대다수는 RDBMS이고, 이 DBMS는 SQL을 사용한다. 그러므로 SQL을 사용하는 것은 RDBMS를 이해할 수 있기 때문에 반드시 알아두어야 한다.
*/
-- 09.1 Row를 read하는 방법
SELECT (column) FROM (table);
/*
Read는 SQL의 기능 중에서 어렵고, SQL을 다루는 수준의 척도가 되기도 한다.
Data를 read하는 작업은 RDBMS에서 굉장히 많은 기능으로 분화되기 때문에 강력하면서도 복잡하다.
어떤 data를 read할지 선택하는 것이 1단계다.
- 모든 column and row를 read해보자.
- sqldeveloper로 더 편리하게 볼 수 있다. (done)
일단 oracle DB 개념을 충분히 이해하는게 우선이다.
*/
/* 모든 column의 row를 read하는 방법 */
SELECT * FROM topic;
-- sqlplus에서 table 간격을 수정하는 명령도 있는데, sql developer tool을 사용하면 편리하다.
-- 09.2 Projection : 특정 column or row를 read하는 행위
SELECT id, title, created FROM topic;
/*
Projection처럼 SELECT를 이용한 세부적인 작업들이 있다.
Column이 수 천만개면 모두 읽을 필요는 없을 것이다.
특정 column만 보고싶다.. 확인할 필요가 없는 column을 hide하는 작업은 projection이라고 한다.
*/
/* Projection for specific row(s) */
SELECT * FROM topic WHERE id=1; -- Column을 제한해서 보는 것 말고, 특정 조건에 따라 특정 row만 read하고 싶을 때 사용하는 query
/* Column과 row를 모두 제한해서 read하는 방법 */
SELECT id, title FROM topic WHERE id > 1;
-- 09.3 Order에 따라 row를 read하는 방법
SELECT * FROM topic ORDER BY id DESC; -- DESC는 descending order. Ascending order는 ASC
/*
SELECT * FROM topic; 이런거 하면 다른 일 못한다. 엄청 오래 처리되기 때문이다.
그래서 원하는 row만 read하는 기술을 알고 있어야만 한다.
이를 page라고 한다.
DB에도 물리적한계가 있기 때문에 page기법을 활용해야 한다.
*/
/* Page에 따라 row를 read하는 방법 (매우 중요) */
SELECT * FROM topic
OFFSET 1 ROWS; -- OFFSET은 index
/*
0부터 count되므로, 이 paging기법은, 'OFFSET 1에 저장되어있는 row부터 가장 마지막 row까지' read하는 명령
이렇게 OFFSET을 사용하여, 지정한 index의 row부터 read할 수 있는데, 여기에 더해 '몇 개를 read할지 결정'하는 것을 FETCH라고 한다.
*/
/* Page에 따라 FETCH해서 row를 read하는 방법 */
SELECT title, description FROM TOPIC
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY;
/*
이렇게 하면, indexing된 row를 시작으로 몇 개를 read할지 보여준다.
결론적으로 FETCH NEXT (num) ROWS ONLY는 '하나의 page가 (num) 개의 row data를 가져온다'는 의미
OFFSET을 활용해서, page를 indexing하여 read할 수도 있다.
*/
-- 10 Row를 update(수정)하는 방법
UPDATE topic
SET
title = 'MSSQL',
description = 'MSSQL is ...'
WHERE -- 반드시 함께 사용해서 updation row에 대해 지정해야한다.
id = 3;
commit; -- 반드시 해줘야 updation이 적용
-- 11.1 Row를 delete하는 방법
DELETE FROM topic WHERE id = 3;
commit;
/*
반드시 WHERE를 붙여야 한다. 안그러면 table data모두 삭제된다.
반드시 해줘야 delete가 실제 db에 적용
*/
-- 11.2 Table을 delete하는 방법
DROP TABLE topic;
/*
Table 자체를 삭제할 때는 DROP TABLE을 사용한다.
commit을 명령할 필요가 없다.
*/
-- 12 Primary Key (기본 키)
SELECT id, title, created FROM topic;
/*
값을 추가하는 행위의 관점에서, ID colmun은 identifier의 기능이 크다.
식별자의 가장 큰 특징은, data가 중복되지 않도록 하는 것이다.
id가 2인 또 다른 row가 있다면, 데이터 중복성 issue다.
그러므로 identifier는 중복되면 안 된다.
예를 들어, 엄청 많은 데이터에서 id가 3인 객체를 추가하려고 하는데,
수 많은 데이터중에 중복되지 않는지 직접 따져보기는 사실상 불가능하다.
id가 3인 data를 추가하려고하는데, destination table에 id가 3인 row가 이미 있는지 검사한 후,
만약 있다면 실행시키지 않고, 없다면 실행하도록 하는 기능을 사용한다면
추가된 id = 3인 객체가 유일무이한 식별자임을 확증할 수 있다.
이를 primary key(기본키, 주 키)라고 한다.
topic table은 여태까지 primary key를 지정하지 않고 다뤄왔다.
Primmary key 지정은, table 생성 시점에 할 수도 있고, 이미 생성된 table에서 ALTER 명령어를 통해 할 수도 있다.
하지만, 가급적 처음에 table 생성시점부터 하는게 좋다.
나중에 data가 엄청 많은 상태에서 primary key를 추가하는 것은 부담스러운 작업일 수 있기 때문이다.
일단 table을 삭제하고 다시 primary key를 지정해서 생성해보자.
*/
CREATE TABLE topic (
id NUMBER NOT NULL,
title VARCHAR2(50) NOT NULL,
description VARCHAR2(4000),
created DATE NOT NULL,
CONSTRAINT PK_TOPIC PRIMARY KEY(id)
);
/*
CONSTRAINT는 제약조건을 말한다.
Primary key는, 제약 조건같은 개념이기 때문이다.
'이미 동일한 primary key가 존재하지 않는 경우에만, table에 data로 저장될 수 있다는 제약 조건'을 지정하는 것이다.
PK_TOPIC처럼 primary key에 대한 '고유한 이름'을 붙여준다.
PRIMARY KEY는, PK_TOPIC이라는 이름을 가진 제약 조건이 primary key로 기능하도록 지정한다.
그렇다면, 어떤 column에 primary key 조건을 지정할 것인지 함께 지정해줘야 한다.
만약 PRIMARY KEY(id, title)처럼 지정하면, 두 column들이 모두 primary key로 작동하는 것이다.
이런 것은 복합키 (complex key)라고 말한다.
*/
/* Primary Key에 의한 Error */
INSERT INTO topic
(id, title, description, created)
VALUES
(1, 'Oracle', 'Oracle is ...', SYSDATE);
INSERT INTO topic
(id, title, description, created)
VALUES
(2, 'MySQL', 'MySQL is ...', SYSDATE);
INSERT INTO topic
(id, title, description, created)
VALUES
(2, 'SQL Server', 'SQL Server is ...', SYSDATE);
commit;
/*
ORA-00001: unique constraint (MYUSER.PK_TOPIC) violated
INSERT INTO 로 row를 추가하는데, 만약 동일한 value의 id가 이미 table에 있다면, 이 error가 발생
참고로 VS Code Oracle SQL Developer Tools에서 위의 code를 를 한 번에 실행하면, 정상적으로 작동하지 않는다.
현재 지정된 code line의 statement만 실행되기 때문이다.
Terminal에서 시도하면, 정상적으로 작동한다.
만약 1, 2까지 insert into하고, 마지막에 중복 id로 insert into한 후에 commit하면,
제약조건에 걸리지 않은 query는 모두 정상작동했으므로 table에 저장된다.
아무튼, 이렇게 table에 primary key를 지정하고 data를 추가하면 row를 read하는 속도에서 엄청난 효율이 있다.
SELECT id, title FROM topic WHERE id = 2;
이러한 query를 요청했을 때, primary key가 지정되지 않은 경우와 이미 지정된 경우의 read 속도를 비교하면 엄청나게 큰 차이가 있다.
그러므로 primary key를 지정하지 않은 table에서 data를 탐색해내려면 아주 느리므로, 반드시 table을 만들 때 사용하자.
*/
-- 13 SEQUENCE라는 도구의 사용법 */
/*
Primary key로 무엇을 할 수 있는지 알아보자.
예를 들어 4번째 row를 추가해보자.
그런데 기존 table의 id value가 가장 큰 row를 찾고 거기에 1더하는 식으로 초기화할 수도 있다.
하지만 이렇게 연산되는 동안에 다른 사용자에 의해 추가되는 이슈로부터 안전하지 않다.
그러므로 oracle이 제공하는 기능이 있다.
Sequence의 사용법 을알아보자.
*/
CREATE SEQUENCE SEQ_TOPIC; -- Sequence를 생성하는데, 'SEQ_TOPIC'이라 명명했다. topic을 위한 sequence
/*
Sequence가 생성되었다. 이를 이용해서 id로 초기화될 value가 1씩 증가하면서 data를 row에 추가하는
기능을 사용할 수 있다.
*/
INSERT INTO topic
(id, title, description, created)
VALUES
(SEQ_TOPIC.NEXTVAL, 'MongoDB', 'MongoDB is ...', SYSDATE);
/*
생성한 sequence name은 SEQ_TOPIC이다. 이 identifier를 사용하여 추가하면 된다.
dot notation(.)과 nextval에 대해서는 아래의 reference를 참고하자.
docs.oracle.com/cd/A84870_01/doc/server.816/a76989/ch26.htm
SEQ_TOPIC이라는 sequence의 값은 0으로 초기화되어있는데,
1을 더한 연산 결과를 NEXTVAL로써 SEQ_SEQUENCE에 return하도록 작동한다.
우선 table을 모두 삭제하고, INSERT INTO에 SEQ_TOPIC.NEXTVAL을 사용하여 table을 생성해보자.
*/
SELECT SEQ_TOPIC.CURRVAL FROM topic;
/*
Sequence의 현재값을 알고 싶을 때에는 위와같은 명령어를 사용한다.
하지만 이렇게 하면, topic table에 있는 row의 갯수만큼 current value가 출력되므로 불편하다.
*/
SELECT SEQ_TOPIC.CURRVAL FROM dual;
/*
Topic같은 예제 DB말고, 실제 데이터를 다루는 db를 다루기는 위험할 수 있다.
그럴 때에는 dual이라는 가상적인 table을 활용해준다.
참고로 sequence는 primary key와 아주 밀접하다.
이 두 가지를 함께 이해해야 더 강력하게 sql을 사용할 수 있다.
*/
-- 14 Server & Client
/*
Oracle DB가 설치되어 있는 컴퓨터(S)
또 다른 컴퓨터(C)에는 SQL Plus가 설치되어 있다고 생각해보자.
인터넷에 연결되어 있는 디바이스 하나 하나를 Host라고 말한다.
그렇다면, S와 C 모두 Host다.
참고로 DB의 HOST가 무엇이냐는 것은, DB가 설치된 컴퓨터의 IP나 Domain을 묻는 것이다.
네트워크에 연결된 디바이스가 모두 host라고 하는 것은 약간 부족하기도 하다.
C는 data를 요청하는 기기이고, S는 응답을 하는 기기라는 차원에서 그러하다.
그러므로 두 컴퓨터는 서로 역할이 다르기 때문에 다르게 언급하는데,
정보를 요청하는 C같은 host를 Client라고 하며
응답해주는 S같은 host를 Server라고 한다.
이 두 개념은 인터넷/네트워크를 이해하는 핵심 개념이다.
DB에 대하여 여러 user가 접근할 수 있다는 것을 생각해보면, 아래와 같은 경우를 상상해볼 수 있다.
Server : Oracle Server
Client 1 : which is installed sqlplus (User1)
Client 2 : which is installed sqlplus (User2)
Client 3 : which is installed sqlplus (User3)
Client 3대 모두 Oracle Server에 network로 연결되어 있다.
서로 다른 공간에서 Oracle DB를 사용할 수 있다.
이 맥락에서, Server에 설치되어있는 software를 Oracle DataBase Server라고 말하고,
이 DB Server에 요청하는 역할을 하는 program들을 Oracle DataBase Client라고 말한다.
구체적으로는 sqlplus가 그러한 프로그램이다.
즉 oracle server와 sqlplus는 서로 다른 프로그램인 것이다.
이러한 관계에서 유용한 점이 있다.
sqlplus로 db에서 manipulation하는 것이 번거로운데, GUI환경에서 Server에 정보를 요청할 수 있다.
대표적인 예시로 SQL Developer가 있다.
*/
-- 16.1 Table의 분해/조립 - 분해하기
/* Relation */
/*
RDBMS는 table 구조로 data를 다룬다.
Table을 사용하다보면, table이 매우 커지는데, rdbms에서는 table을 쪼갤 수도 있고
조합도 할 수 있어서, 실제로 db에 원형으로 저장되어있는 table이 아닌 형태로도 사용가능하다.
이 Relation이 매우 중요하다.
topic table에 name, profile 이라는 column을 더 추가한다고 생각해보자.
name에는 이름(Egoing, Egoing, Duru)을, profile에는 업무직군을 적어보자. (Developer, DBA)
이런 table에 문제가 없어보이지만, 정보공학적으로 극단적인 관점에서 보면 문제가 있다.
이 table에 row가 3개인데, 만약 1억개라면?
1억개인 경우에서 발생하는 심각한 issue
- Egoing이라는 사람이 자기 profile을 Manager로 바꾸려고 한다면?
1억개의 row data에서, Egoing이 name column에 있는 모든 row에서 profile을 manager로 바꿔야한다.
이걸 단순히 처리하는데 엄청나게 오랜 시간이 소요될 수 있다.
왜냐하면, Egoing이라는 data가 중복되었기 때문에 발생하는 issue다.
- 첫 번째 Egoing과 두 번째 Egoing이 실제로 다른 사람이라면?
수정이 필요한 Egoing을 기술적으로 한 번에 수정하는 것이 어렵다.
- Taeho라는 사람이 저자인데, 아직 topic에 들어갈 data를 만들지는 않았다.
그렇다면, Taeho는 이 table에 input될 수 없다.
즉 DBMS에 존재할 수 없다.
이러한 issue들을 해결하는 극적인 방법이 바로 table을 분해하는 것이다.
*/
/* Table Split */
/*
name, profile에 대한 table을 따로 분리시킬 것이다.
이 table_name은 author이고,
column으로 id, name, profile이 구성되어 있다.
id name profile
1 Egoing Manager
2 Duru DBA
이런 구조다.
그리고 topic table에는 author_id 라는 column을 추가한다.
그렇다면, topic.id 1, 2에 대응하는 author_id는 1이고,
topic.id 3에 대응하는 author_id는 2다.
이렇게 구성된 topic table에서 read한다면?
first row를 read할 때, author_id가 1이므로, author table을 참조해서
egoing이고 manager임을 알 수 있다.
다시 Egoing의 Profile을 developer로 생각하고 짚어보자.
앞서 developer인 egoing을 1억 번 수정했어야 했다.
예를 들어 row하나가 1기가의 data라면 매우 심각한 비효율이 발생할 수 있다.
그런데 author table을 따로 분리시켜서 생성해놓았으니,
이 table의 row 하나만 manager로 수정하면, topic table의 1억 개 행에서
author_id = 1인 모든 row가 수정될 수 있다.
3 Taeho Data Scientist
그리고, 글을 한 번도 쓴 적이 없는 사람은 author table에서만 존재하게 할 수 있다.
4 Egoing Developer
만약 이름이 Egoing이고 직업이 developer인 동명 이인이 있다면, 이 사람 역시
author table에서 별도의 id를 부여받음으로써 id = 1인 Egoing과 다른 존재임을 나타낼 수 있다.
이렇게 table을 relation에 따라 split하고, 다시 조립하는 것은
관계형 데이터베이스에서 아주 중요하다.
*/
-- 16.2 Table의 분해/조립 - 조립하기
/*
앞서 만든 첫 번째 topic table은, update하기 너무 불편하다.
Read하기는 좋지만, Write에 너무 비효율적이다.
반면에 table split으로 만든 구조에서 topic table은 wrtie하기 편리하다.
author table의 id만 바꾸면, 이 data를 참조하는 topic table의 author_id가
바뀌기 때문이다.
하지만 read하기 불편하다.
read할 때마다 author table을 참조해서 해당 row의 data를 read하기 때문이다.
그러므로, 첫 번째 topic table이든 두 번째 table이든 장단점이 있다.
그럼 공학적인 마인드로 접근해보자. 공학은 trade-off(균형)를 고민한다.
이 두 개의 구조를 합성해서 새로운 구조를 만들어내보자!!
이를 도와주는 기술이 바로 JOIN이다.
Join은 결합한다는 의미다.
즉, table을 split한 다음에, 필요에 따라 table을 조립해서, 마치 그러한 구조의 table이
존재하는 것처럼 만들어내는 기능이다. illusion!
이번 chapter에서는 join에 대해 자세하고 적당하게 짚어보자.
엑셀의 두 번째 topic table에서 보이듯이,
table을 저장할 때에는 table을 split해서 저장하지만,
table을 read할 때에는, 마치 '첫 번째 topic table처럼 결합된 형태'로 저장되어 있는 것을
read하는 것처럼, read한다.
그럼 이런 경우에 어떻게 SELECT를 사용하는지 살펴보자.
*/
SELECT * FROM topic LEFT JOIN author ON topic.author_id = author.id;
/*
이 query는 oracle DB에 관계적인 테이블을 illusion으로 보여주는 기능을 한다.
topic table을 가져오는데, join시킬 table 기준(author)으로 왼쪽에 결합시킨다.
그렇다면, topic table의 각 row에, 어떤 관계에 따라 join시킬지 지정해야 하므로,
ON 명령어 뒤에 그 condition을 작성해준다.
topic.author_id는 'topic table의 author_id column'을 의미한다.
author.id는 'author table의 id column'을 의미한다.
그러므로, 이 expression은 두 operand가 동일한 관계를 가지도록 table을 join시킨다는 것이다.
TOPIC AUTHOR
ID TITLE DESCRIPTION CREATED AUTHOR_ID | ID NAME PROFILE
1 Oracle Oracle is ... 17-Feb-23 1 | 1 Egoing Developer
2 MySQL MySQL is ... 17-Feb-23 1 | 1 Egoing Developer
3 SQL Server SQL Server is ... 17-Feb-23 2 | 2 Duru DBA
JOIN은, 이러한 구조의 table로 저장된 것처럼 illusion을 만들어 data를 read할 수 있도록 한다.
*/
-- 16.3 Table의 분해/조립 - 분해 실행하기
/*
먼저 author table을 생성하자.
id, name, profile, 그리고 primary key로 id를 지정하자.
id는 NUMBER, name과 profile은 VARCHAR2 로 data ype을 지정하자.
primary key는 아래와 같이 지정하면 된다.
*/
CONSTRAINT PK_AUTHOR PRIMARY KEY(id)
/*
그러면 이제 table이 생성되었다.
참고로, sqldeveloper의 gui환경에서 new table로 할 수도 있다.
이 때, DDL 탭으로보면 SQL로 어떤 query인지 알 수 있다.
이제 topic table에 author_id column을 추가해줘야 한다.
*/
ALTER TABLE topic
ADD
author_id NUMBER;
commit;
/*
이렇게 해주거나, gui에서 topic table을 열고, edit 버튼을 클릭해서 추가할 수도 있다.
이제 sequence를 지정해서, author table의 data가 추가될 때 마다 topic table의 author_id를 1씩 증가시킬 것이다.
*/
CREATE SEQUENCE SEQ_AUTHOR;
/*
이제 author table에 data를 추가해주자.
id를 추가하는데에 seq_author를 사용할 수도 있지만 복잡해질 수 있어서 일단 그냥 sql문으로 추가해주자.
*/
INSERT INTO author
(id, name, profile)
(SEQ_AUTHOR.nextval, 'Egoing', 'Developer');
commit;
/*
이 script를 실행하면, author table에 data가 추가된다.
이제 topic table의 author_id column에 Egoing의 id를 넣어주자.
그리고 다시 author table에 duru, taeho에 대한 data를 넣어주고, 마찬가지로 topic table의 author_id에 id를 넣어준다.
참고로 sqldeveloper에서 scrip의 실행 단위는 현재 커서를 기준으로 한다.
즉 해당 커서의 행만 실행되는 것이다.
이런 과정을 거쳐 split table을 완성했다.
다음 chapter에서는 JOIN을 해보자.
*/
-- 16.4 Table의 분해/조립 - 조립 실행하기 : JOIN
/*
JOIN을 사용해보자.
앞서 author table과 topic table을 split해서 store해놓았다.
저장은 분리되어 있지만 read할 때는 join시켜서 마치 join된 상태로 table이 존재하는 것처럼 사용할 수 있다.
이를 위해 JOIN을 사용해보자.
*/
SELECT * FROM topic;
/*
이렇게 명령하면, 앞서 update한 topic table의 author_id column도 함께 보일 것이다.
Author table의 id column의 data는 primary key value다.
즉 이 primary key value가 author_id column에 저장되도록 했었다.
이처럼, 연관된 table의 primary key value를 저장해놓은 column을, foreign key라고 말한다.
물론 foreign key라는 기능이 있기는 하지만, 개념적으로 이러한 것이다.
이제 topic table을 read하는데, topic table의 row를 기준으로 하여, author table의 row를 join시켜보자.
Topic table을 왼쪽에 두고, 이를 기준으로 오른쪽에 author table을 결합시킬 것이다.
*/
SELECT *
FROM topic
LEFT JOIN author
ON topic.author_id = author.id
;
/*
이렇게 ON 명령어 뒤에 어떤 condition에 따라서 두 table을 relation시킬지 지정해야 한다.
topic table의 author_id와, author table의 primary key인 id가 일치하는 row를 결합시키는 것이다.
이것이 RDBMS의 핵심이다. 조금 더 자세히 살펴보자.
sqldeveloper의 실행 결과를 보면, ID column이 두 개이고, 잘 분간이 가지 않는다.
*/
SELECT
id,
title,
name
FROM topic -- id is ambigious
LEFT JOIN author
ON topic.author_id = author.id
;
/*
또는 id, title, name을 read하고 싶다고 했을 때, column ambigious하다고 error가 나타난다.
왜냐하면 id라는 column은 topic에도 있고, author에도 있기 때문이다.
*/
SELECT
topic.id,
title,
name
FROM topic -- specify the table of column : topic.id
LEFT JOIN author
ON topic.author_id = author.id
;
/*
이럴 때는 어떤 table의 id인지 topic.id처럼 명확하게 지정하면 된다.
그런데 table을 설계한 입장에서 스크립트 실행결과 나타나는 table의 id가 topic의 id인 것은 알지만,
다른 사람은 모를 수 있다.
*/
SELECT
topic.id TOPIC_ID,
title,
name
FROM topic -- Specify alias of a column : TOPIC_ID
LEFT JOIN author
ON topic.author_id = author.id
;
/*
이런 경우를 위해, column_name을 임의 지정해서 표현해줄 수 있다.
즉 column에 대한 alias를 지정하면 된다.
*/
SELECT
T.id TOPIC_ID,
title,
name
FROM topic T -- Alias of table 'topic' : T
LEFT JOIN author A -- Alias of table 'author' : A
ON T.author_id = A.id
;
/*
그리고 이 table자체에 대한 alias를 지정할 수도 있다.
그러면 해당 query 전체에서, 그 alias를 사용할 수 있는 것이다.
여기서는 topic table을 T, author table을 A로 alias지정했다.
*/
SELECT
T.id TOPIC_ID,
title,
name
FROM topic T
LEFT JOIN author A
ON T.author_id = A.id
WHERE
T.id = 1
;
/*
만약 topic table의 id가 1인 row만 read하려면, 이렇게 WHERE문 명령을 할 수 있다.
*/
-- 16.5 더 배워볼 것
/*
- Relational Data Modeling (관계형 데이터 모델링)
Relational Database를 잘 사용하는 것은 인생을 갈아 넣어도 쉽지 않다.
현실의 문제를 RDB에 넣으려면 천재적인 table을 구성해야 하기도 한다.
이 때, 이러한 table을 설계하기 위한 다양한 방법론이 있다.
이런 방법론을 모아서 정립해놓은 것이 관계형 데이터 모델링이다.
좋은 table을 만드는 표준화된 방법론이 집대성되어 있다.
- Index에 대한 이해
정보가 많아지면, 원하는 정보를 찾아내기 어려워진다.
Index는 data가 write될 때, 미리 정리정돈해두는 것을 의미한다.
이렇게 해놓으면, 1시간짜리 read 작업을 1초에 끝내버릴 수 있는 magic같은 것이다.
- Middleware의 사용법
이번 수업에서는 직접 DB를 다뤘지만, 실제로 실무에서 이렇게 직접 DB를 다루는 경우는 많이 없다.
오히려, 웹/앱 등 다양한 종류의 장치를 통해 사용자의 정보, 글, 또는 장비가 생성한 data를 db에 보관한다.
이 때, user가 사용하는 UI와 DB 사이에 존재하는 중간 역할을 하는 것이 Middleware다.
[ User - UI - MiddleWare - Oracle ]
Middleware의 사용법을 익히는 것도 좋다.
범java진영의 jsp, 서블릿, 스프링이 있고,
php, python, node ju, ruby 등의 기술들도 Oracle의 middleware로 활용될 수 있다.
*/