두 테이블의 참조 관계에서, A B테이블의 관계가 1:N Relationship을 맺을 때, A 테이블의 해당 키를 참조키(Reference Key)라 하고, B 테이블의 해당 키를 외래키(Foreign Key)라 한다

ON DELETE/UPDATE 시 적용될 Cascade 의 종류는 다음과 같이 분류된다.


(1)  CASCADE : 참조키가 삭제/수정 되면 외래키도 삭제/수정된다.


(2)  RESTRICT : 참조키가 삭제/수정 되는 것을 방지한다.


(3)  SET NULL : 참조키가 삭제/수정 시 NULL로 만든다.


(4)  NO ACTION : 참조키가 삭제/수정 시 변동이 안생긴다.


실무에서는 물리적으로 FK를 적용하는 경우가 드물기 때문에 복잡한 종류의 마스터 데이터이거나 비즈니스 로직보다 데이터의 일관성이 중요한 경우가 아니라면 잘 사용은 안한다. 

하지만 물리적으로 연결하게 된다면 상황에 따라 FK 참조 방식을 설정할 때가 있다. 잘 알아두어서 필요할 때 적절하게 사용할 필요가 있다.


 ACID는 Atomicity, Consistency, Isolation, Durability 의 약자로 Transaction이 안전하게 수행된다는 것을 보장하기 위한 성질을 가리키는 약어이다.


트랜잭션의 처리는 Index 의 업데이트 와 같은 신경써주어야 하는 많은 변화를 수반하기 때문에 복잡한 문제이다.

ACID 원칙은 복잡하고 에러 발생 가능성이 높은 트랜잭션 상황에서도 반드시 보장해 줄 수 있는 Database 가 트랜잭션을 지원한다면 가져야 하는 성질이다.


Atomicity : 원자성은 Transaction과 관련된 작업들이 부분적으로 실행되다가 중단되지 않는 것을 보장하는 능력이다. 원자성은 중간 단계까지 실행되다가 실패하는 일이 없도록 하는 것이다. All or Nothing. 즉, 모든 작업이 성공하거나 실패한다.


- Consistency : 일관성은 Transaction이 실행을 성공적으로 완료하면 언제나 일관성있는 Valid 한 DB 상태를 유지하는 것을 의미한다. 여기서 Valid 한 상태는 트랜잭션의 결과로 업데이트된 데이터가 각종 Constraints 및 Rule 을 위반하지 않는 것을 의미한다. 무결성 제약에 위반하는 Transaction은 중단된다.


- Isolation : 고립성은 Transaction을 수행 시 다른 Transaction의 연산 작업이 끼어들지 못하도록 보장하는 것을 의미한다. 이는 Transaction 밖에 있는 어떤 연산도 중간 단계의 데이터를 볼 수 없음을 의미한다. 또한 고립성은 Transaction 실행 내역이 연속적이어야함을 의미하고, 유연성있는 제약조건이다.


- Durability : 지속성은 성공적으로 수행된 Transaction은 영원히 반영되어야 함을 의미한다. System 문제나 DB 일관성 체크 등을 하더라도 유지되어야 하고, 모든 Transaction은 로그로 남긴 채로 Rollback도 가능하다. 

Transaction은 로그에 모든 것이 저장된 후에만 Commit 상태로 간주한다.


Database는 트랜잭션에 연관된 모든 연산들을 한번에 실행하기 쉽지 않다. 

서로 강하게 결합되어 있는 연산들의 정렬 기준이 복잡하기 때문이다. 이 문제를 해결하기 위하여 DB는 연산의 처리 시 로깅을 이용하여 모든 작업에 대한 변경사항을 로그로 기록한다. 


ACID 를 보장하기 위한 방법으로 처리하는 데이터에 대해 Lock을 걸어서 관리하거나 MVCC라 하여 데이터의 복사본을 만들어두어 동시 처리 후 충돌을 후처리 하는 방안이 있다.






 많은 경우 조인과 서브쿼리를 통해 복잡한 쿼리 연산을 수행할 수 있으나 쿼리만으로 두 테이블의 다른 항목들을 열거하는 작업은 UNION 을 사용하면 아주 간단해진다.


 다음과 같은 규칙만 만족한다면 N개의 다양한 테이블을 하나의 쿼리로 연결한 SELECT 결과를 받을 수 있다. UNION은 다음과 같이 사용가능하다.


* SELECT name from professor UNION select name from girl_group


 위의 쿼리에서 우리는 Professor 테이블의 존재하는 name 들과 girl_group 테이블 내에 존재하는 name 들을 얻을 수 있다. 교수들의 이름과 걸그룹의 이름을 같이 얻을 수 있겠다.(;;)


(1) UNION 내에서 쿼리들은 하나의 ORDER BY만 사용한다. UNION 으로 감싸는 쿼리들을 각각 정렬하는건 허용되지 않는다.


(2) 각 SELECT의 열수, 표현식이 같아야 한다.


(3) SELECT 문들끼리의 순서는 상관없다.


(4) 결과가 중복되면 DEFAULT 설정으로는 하나만 나온다.


(5) 열의 타입은 같거나 반환 가능한 형태여야 한다.


(6) 중복값을 나타내고 싶다면 UNION ALL을 사용한다.


 물론 UNION 내의 쿼리들을 각각 정리하는 편법은 존재한다. 바로 서브쿼리를 이용하면 가능한데 예를들어 다음과 같이 하면 된다.


SELECT * from (select name from professor order by reg_date)

UNION ...

SELECT * from (select name from girl_group order by reg_date)


위의 예시는 교수의 이름들을 등록 시간 별로 정렬해서 name 을 묶고, 걸그룹의 이름들을 등록 시간 별로 정렬해서 묶는 쿼리의 모습이다.


 EXPLAIN 은 어느정도 수준있는 DB를 다루는 개발자라면 꼭 알아야할 정도로 중요한 MySQL 의 쿼리문이다.


 실제로 많은 데이터베이스 관련 서적들에서도 최적화를 위한 선행 단계로 추천하고 있을 만큼 MySQL 의 강력하고 효과적인 쿼리문이다.


 EXPLAIN 키워드는 MySQL 에게 쿼리문의 실행 계획을 물어보는 키워드이다.


 Explain 구문을 이용해서 SQL Query를 수행하기 전에 데이터를 어떻게 가져올 건지에 대한 시스템의 실행계획을 받아볼 수 있다.

주로 쿼리 퍼포먼스 측정을 위해 Explain 을 많이 사용하지만 매 쿼리를 코드에 삽입할 때 테스트해보는 습관을 들이는 것이 좋다.

 

 SELECT 구문에서 explain 을 사용하는 방법은 단순히 키워드 앞에 붙여주기만 하면 된다. 단 SELECT 구문이 아닐 경우에는 INSERT, UPDATE, DELETE 등의 구문을 SELECT로 재구성시켜줘야 한다.


(ex) EXPLAIN select * from members

      UPDATE name from members where member_id = ‘1’

       EXPLAIN SELECT name from members (UPDATE 후)


 EXPLAIN 에서 각 칼럼은 다음과 같은 의미를 갖는다.


Select_type – 간단한 쿼리인지 복잡한 쿼리인지를 나타낸다.


Table – 어떤 테이블에 접근하는지를 나타낸다. 복잡한 쿼리문에서도 어떤 테이블에 실질적으로 접근하는지를 알 수 있다.


Type – 조인 방식이자, 테이블에서 해당 레코드를 어떻게 찾아가는지를 나타내며 퍼포먼스 측정에 있어서 중요한 지표이다. 

(ALL-풀스캔, INDEX-유사 풀스캔, RANGE-제한된 인덱스 스캔, REF-부분적인 값에 매칭되는 부분만 검사, EQ_REF-단 하나의 

값만 참조하는 경우, CONST-쿼리 일부를 상수로 대채시켜서 찾음. SYSTEM-무조건 하나의 열만을 갖는 테이블)


Possible Key- 해당 조회문에서 MySQL이 선택한 인덱스를 나타낸다.


Key – MySQL이 실제로 사용할 키를 나타낸다. 


Key len – 인덱스 필드가 가질 수 있는 최대길이


Ref – 키 칼럼의 인덱스를 찾기 위해 선행 테이블의 어떤 칼럼이 사용되었는지


Row – 원하는 행을 찾기 위해 읽어야 하는 예측 Row 카운트


Extra – 각종 조건문이 사용되는지 여부를 나타낸다.



 특히 많은 종류의 웹서비스가 SELECT 에 대한 처리를 주로 하는 경우가 많다.(SELECT 가 주가 아닌 데이터라면 MySQL 을 사용하지 않을것이다.) 

가령 Key 로 잡히지 않은 Column 을 조건으로 SELECT 쿼리를 수행하는 경우, 특히 유저 DB라면, FULL SCAN 이 발생해 막대한 비용이 들게 된다...


 이런 참사를 개발시에 눈치챌 수도 있지만, 본인이 DB 구조를 잘 모르거나 구조가 매우 복잡한 레거시 프로젝트에 투입된 상황이라면, EXPLAIN 의 생활화는 큰 도움이 될 것이다.






MySQL에서 인코딩을 설정할 때 Collation이라는 개념이 나오는데 이 점은 Character set과는 조금 차이를 보인다.


 Character Set – 특정 문자가 저장될 때 어떻게 Encoding되어 저장될 것인지 규칙이 저장되어 있는 집합 (ASCII, EUC-KR, UTF8 등)


 Collation – 특정 문자셋에 의해 DB에 저장된 값들을 검색하거나 정렬 등 작업을 위해 문자들 간에 ‘비교’ 시에 사용하는 규칙들의 집합.


 이 설정은 일반 type이 아닌 char, varchar 등 데이터 타입을 갖는 칼럼에 적용한다.

Binary 방식(대소문자 구별) 이나 Case Insentive(대소문자 미구별) 방식이 있으며 Case Insentive 방식의 경우 뒤에 ci가 붙는다.


 자주 접하게 되는 내용은 아니지만, 맨처음 MySQL / RDS 를 세팅할 시, 이 개념을 잘 이해하지 못하고 한쪽만 설정해서 컨텐츠의 Encoding 이 깨졌었던 이슈가 있었다. 설정 시에 양쪽 모두 확인하고 알맞게 세팅하는 것이 중요하다.


(참고 linuxism.tistory.com/432)





 Primary key(이하 PK)는 한 개 혹은 여러 개의 칼럼으로 테이블 내의 각 행들을 구별하기 위한 목적을 갖고 있다.

 PK는 그 자체만으로 Unique 하며 만약 여러 개의 Column이 PK로 묶여 있다면, 해당 값들의 조합이 반드시 Unique 해지게 된다.

 PK는 NULL 값을 갖을 수 없고(NOT NULL), Unique key라는 특징을 갖게 된다. 단순하게는 NOT NULL & UNIQUE == PK 라고 생각하면 편하다. 물론 좀더 디테일하게 보자면 차이가 있다.


 MySQL에서는 Int 작업이 빠르기 때문에 PK는 Int형으로 지정하는 것이 좋다. 


 Unique Key(Unique index)는 value의 값을 유일하게 만드는 column의 제약으로 PK와는 조금 다르게 NULL값이 가능하며, 역시 여러 개로 묶어서 Combination Index 를 만드는 것이 가능하다.


 * MySQL에서 Key와 Index는 동의어이다. (PRIMARY KEY 가 아니라 Key 가 Index와 동의어이다. 물론 PK 는 Index로 취급되긴 한다.)

 Unique Key 와 PK 의 차이점은, NULL 허용 여부와 의미 상의 차이가 있다. PK 로 지정된 Column 들은 Table 의 Row 를 구분하는 대표 값들이라는 Identity 를 갖지만, Unique Key 는 그보다는 좀더 제약(Constraint) 에 가깝다. 물론 "Unique" 해야 하기 때문에 구분하는 대표값으로 사용해도 무방하지만, PK 처럼 테이블의 대표값라고 취급하는 것은 위험하다.


 MySQL PK 지정 예시. (생성시)


(ex) Create table t(

id int not null, 

name char(10) not null, 

contents text, 

primary key(id, name));


 MySQL PK 추가 예시. (테이블에 추가)


(ex) Alter table 테이블 Add Primary key(칼럼)


 Key 값 조회하는 방법 예시.


(ex) Show Keys from 테이블



 물론 복잡한 DB 쿼리를 다루었던 프로젝트에서는 데이터 무결성을 효율적으로 관리하던 Constraint 를 본적이 있었지만, 경험상 실무에서 Unique Key Constraint 보다는 주로 PK로 값 연결하는 일이 많았다. 

 Unique Key Constraint 는 데이터 무결성에 있어서 좋은 도구이기는 하나... Constraint 도구들이 실 서비스에서도 유용하다고 볼순 없기 때문에 PK 만큼 유용하게 사용되지는 않는 듯 하다.





MySQL은 레코드 타입에 대해 암묵적인 캐스팅을 지원한다.


 가령 Int형 칼럼에 “12345"로 입력하거나, char형 칼럼에 9999와 같이 입력해도 Int형 칼럼에는 12345가, char형 칼럼에는 “9999"가 입력된다.


 이는 컨버팅 가능한 형에 제한하며 가령 Int형 칼럼에 “amanda"를 입력하면 0으로 삽입된다. 


 그 외 내장으로 Convert(), Cast() 와 같은 함수들이 있는데 이 함수들은 주로 String 데이터의 Character set 및 인코딩 간 캐스팅을 담당한다.


 단순한 내용이지만, 프로그램 구조를 잡을 때 알아두면 편한 경우가 있고,  묵시적 캐스팅을 몰랐다가 CS를 일으키는 경우가 있다. DB 커넥터 쪽에서 에러를 뱉지 않기 때문에, 에러 로그없이 자동 캐스팅으로 인한 문제라도 생겨버린다면 낭패일 수 있다. (물론 그런 경우는 흔치 않다.)


 처음 학부생 때 공부를 위해서 혹은 실무에서 관계형 데이터 베이스를 접하고, 직접 설계하는 일은 쉽지 않다.

많은 DB 테이블들이 직관적으로 나타나있고 관계 역시 이해하기는 어렵지 않지만 이를 구성하고자 한다면 성능, 데이터의 정합성, 중복 배제 등 고려해야할 내용은 많다. 물론 그걸 다 잘하기는 매우 힘들며, 비즈니스 특성에 따라 트레이드 오프를 감안하여 작성하게 된다. ^^;;

 처음 DB 설계를 해보려는 이들에게 이번 정리 내용의 포스팅은 큰 도움이 될 수 있다.


 * RDB 설계 시작하기 5가지 단계


(1) DB의 목적을 명확히 한다. (Define the purpose of the DB)


(2) 수집한 데이터를 적절히 나눌 수 있는 기준이 될 Primary Key 를 구성한다.


(3) 테이블 간의 관계를 구상한다. 가장 쉬운 관계의 형성은 PK를 중심으로 생각하는 것이다. 


- One to many : Parent 테이블의 모든 value는 많은 Child table의 Record를 가질 수 있으나 Child table의 모든 Value는 Parent table에서 단 하나의 Record에 대응되어야 한다.


- Many to many : Many to many의 관계는 일반적으로 다수의 one to many 관계들로 이루어질 수 있어야 한다.


- One to one : 주로 동등한 레벨의 정보에 대한 Column 분리 용도로 사용된다.


(4) Refine and Normalize the Design(정규화)


 Column의 추가나 Optional data 처리를 위한 table 분리 등.


- 1NF : 기본적으로 필요한 속성들을 하나의 entity로 모아놓고 하나의 속성을 UID로 선정했다면 0NF 상태이고, 여기서 Repeating group을 제거하면 1차 정규화 형식이라 한다.


- 2NF : 속성들이 PK의 일부에 대해서만 종속적이라면 이 Part key dependency를 제거하여 2NF 형식이 된다.


- 3NF : 2NF에서 Key가 아닌 다른 속성에 종속적일 때 Inter-data dependency라 하며 이를 제거하면 3NF 형식이 된다.


- BCNF : Key 내의 속성이 key 내의 다른 속성에 종속적이라면 Inter-key dependency라 하며 제거하면 BCNF 형식이 된다.


(5) Denormalize : 순수히 성능만을 위한 기법이다.

- Comined table : 자주 조인하는 테이블의 경우 조인 성능부하를 없애기 위해 미리 Join된 형태로 table에 합침. 그럴 수 없는 경우 Join overhead는 Index나 SQL Plan을 조정한다.


- Derived data : 계산해서 얻을 수 있는 값을 굳이 칼럼으로 따로 빼준다.


- Artificial key : 적절한 PK가 없거나 인덱싱이 힘든 경우 간단한 AK를 만들어 해결하고 PK column은 일반속성화 한다. (예를들어 굳이 나뉘어져있지 않은 기수 번호를 인공적으로 Key로 만들어주어 부여하고 이를 인덱싱하여 성능을 개선한다.)


- Denormalization 의 예시. 유저 정보 테이블 id, name, address. 유저 성적 테이블 id, score. 두 테이블의 조인이 빈번하다면 두 테이블을 합칠 수 있음. Id, name, address, score.



 * 추가적으로 좀 더 자세한 설명이 필요하다면 다음 링크가 정말 잘 정리되어있다.  http://www.ntu.edu.sg/home/ehchua/programming/sql/relational_database_design.html






 RDB에서 관계를 맺는데 있어서 식별관계(Identifying Relationship)와 비식별관계(Non-Identifying Reltationship)가 존재한다.

정확히는 RDBMS에서 나누는 관계가 아닌 ER Diagram 상에서 논리상 나누는 개념이며... 굉장히 헷갈린다.


 Identifying Relationship 은 부모 테이블의 기본키 또는 복합키가 자식 테이블의 기본키 또는 복합키의 구성원으로 전이되며, 관계는 서로 종속되게 된다.


 예를 들어서 B라는 테이블의 FK child A 테이블의 PK를 참조한다면 Identifying Relationship에서 B테이블은 A 테이블에 종속이 되어서 A값이 없으면 B값은 홀로 의미를 갖지 못하는 관계가 된다. 아래의 테이블을 보자


<학생 정보를 기록하는 TableA 와 학생 성적을 관리하는 TableB>


위의 테이블에서 tableA는 학생들의 정보를 기록하는 테이블이고, tableB는 학생들의 과목별 성적을 기록하는 테이블이 된다.

TableA와 TableB는 똑같이 studentId를 PK로 갖고 있으며, TableB 에서 studentId 가 없다면 TableB는 독립적으로 존재할 수 없는 정보가 된다. 이때, 우리는 학생의 성적은 학생에게 종속되어 있다는 사실을 기반으로 생각하기 때문이다. 이러한 Strong coupling 에 대한 관계가 Identifying Relationship 이다. 


 반면에 Non-Identifying Relationship 은 자식 테이블의 일반 속성(Attribute) 그룹의 구성원으로 전이되는 비식별관계로부모는 자식의 부분적인 정보만을 표현함을 의미한다위의 예에서 Non-Identifying Relationship 의 경우 B테이블의 값은 A FK의 관계를 맺고 있긴 하지만 독립적으로 존재할 수 있어야 한다.(즉, FK가 B테이블의 PK가 되어선 안된다.) 이제 위의 테이블을 Non-identifying 한 관계로 바꾸어보자.


<학생 정보를 기록하는 TableA 와 학생 성적을 관리하는 TableB>


변경된 테이블에서 TableB는 더이상 studentId를 키로 갖지 않는 대신 별도의 독자적인 subjectId를 키로 가진다. 그리고 학생정보를 기록하는 TableA가 이를 참조하는 방식으로 변경되었다. TableB의 subjectId는 특정 성적의 기록이 되며, 성적의 기록을 모아둔 성적 기록부가 된다. 학생기록부(TableA)에서 성적기록 태그(subjectId)를 찾으면 이제 해당 학생의 성적 정보가 완성된다. 즉, 두 테이블은 서로가 없이도 유효한 정보를 나타낼 수 있다.


 이해를 돕기 위해 좀 더 편한 예시를 들어보자, 가령 책과 독자와 같은 정보의 경우는 Non-Identifying 관계이며, 독자가 없어도 책은 존재할 수가 있다. 하지만 저자와 책의 경우는 저자가 없는 책이 있을 수 없으므로 Identifying 관계라고 할 수 있다.



 * 관련되어 헷갈린 개념으로 Optional 과 Mandatory라는 개념이 있다. 이는 Non-identifying Relationship에 적용되는 내용으로, 참조하는 Foreign Key가 Null이 될 수 있는가에 대한 내용이다. 가령 위의 예시에서 어떤 학생이 어떤 과목의 시험성적도 갖고 있지 않다면 subjectId는 NULL이 될 수 있다. 학생의 성적 기록이 없기 때문이다. 이 때를 Optional 하다고 하며, NULL이 허용이 안되는 상황, 모든 학생이 입학시험은 적어도 봐야한다고 하면 subjectId는 NULL이 될 수 없다. 이 때를 Mandatory 하다고 한다.


서두에 언급했듯이 이는 ERD 를 그릴때 고려되는 개념이기 때문에 어떻게보면 추상적인 개념이라고 할 수 있다. 실무에서 ERD를 그릴 때 모른다면 실수로 잘못된 커플링을 갖거나 NULL이 허용되는 상황에서 NULL이 허용되지않는 관계가 생겨날 수도 있기 때문에 알아둘법한 지식이다.





SQL이란 DBMS에서 데이터를 질의하기 위해 만들어진 언어이다. 크게 다음과 같이 3가지로 분류된다.


 - DDL (Data Definition Language) : 데이터를 정의하기 위한 언어로, CREATE, DROP, ALTER, TRUNCATE 등으로 시작하는 Query 문이 속한다.
 - DML (Data Manipulation Language) : 데이터를 다루기 위한 언어로 흔히 말하는 CRUD 에 해당하는 SELECT, INSERT, UPDATE, DELETE 등 Query 문이 속한다.
 - DCL (Data Control Language) : 데이터를 관리하기 위한 언어로 주로 사용자에게 권한을 부여하거나 철회할 수 있는 GRANT, REVOKE 등의 Query 문이 있다.


실제로 사용하면서 유용하게 썼던 SQL 쿼리문들을 정리해두었다. 실무에서도 응용해서 사용하면 크게 무리는 없었던 것 같다.

인터넷을 돌아다니다 발견할 수 있는 Geek 한 것들을 모아두진 않았다.


-        접속 방법

 : mysql -u root -p (dbname)


-        비밀번호 변경

 : mysqladmin -u root password 새로운 비밀번호


-        테이블의 생성

 : create table {테이블이름}({칼럼명} {칼럼타입});

(ex) CREATE TABLE member (

id int(11) NOT NULL,

);


-        구조 보기

 : desc 테이블 / explain 테이블  /  show create table {테이블명}


-        이름 변경

 : rename table {테이블명A} to {테이블명B}


-        삭제

 : drop table {테이블명}


-        레코드 삽입

 : Insert into {테이블명} values(v1, v2) / Insert into table(col1, col2) values(v1, v2);


-        조회

 : select * from table {테이블명}


> AS : 칼럼의 이름을 달리 명명해서 출력. (ex) Col1 as 'name'

> Desc : 내림차순, Asc : 오름차순 (ORDER BY)

> LIMIT 10 : 0~10 까지 레코드 수 제한. / LIMIT 100, 10 : 100~110까지 레코드 범위


-        수정

 : Update {테이블명} set col1 = 칼럼1 where 조건


-        삭제

 : Delete from {테이블명} where 조건


-        칼럼 추가

 : Alter table {테이블명} add col3 varchar(255) not null.


-        칼럼 삭제

 : Alter table {테이블명} drop col3


-        칼럼 수정

 : Alter table {테이블명} modify col3 char(50) not null.


-        In : 원하는 필드값만을 선택 추출하는데 사용되는 그룹 조건문


-        조인

(1)  Inner join

 : Select * from tableA inner join tableB on tableA.col1 = tableB.col1

 => tableA col1 tableB col1이 일치하는 데이터만을 출력. ON 절의 조건이 일치하는 조인테이블의 결과만을 출력한다.


(2)  Outer join

 : Select * from tableA left outer join tableB on tableA.col1 = tableB.col1

 => tableA.col1이 존재하나 tableB.col1이 존재하지 않으면 tableB.col1 = NULL인 상태로 출력. 조인하는 테이블의 ON 절 조건 중 한쪽의 모든 데이터를 가져옴(LEFT JOIN , RIGHT JOIN) 양쪽(FULL JOIN)

 

-        내장함수 Benchmark

 : Select Benchmark(반복횟수, 실행쿼리)

(ex) Select Benchmark(100, (select * from table)); => 해당 쿼리를 100번 반복한 벤치마크 결과를 출력.


-        DISTINCT

 : 주로 UNIQUE COLUMN이나 TUPLE을 조회할 때 사용되는 키워드. 칼럼을 DISTINCT 를 이용하여 조회한다면 중복을 제거한 값들을 바로 얻을 수 있다. 단 이 때, 여러 개의 칼럼을 지정한다면 칼럼의 조합이 중복되는 것을 제외한다. DISTINCT는 함수처럼 WHERE이 아닌 HAVING 조건식에도 사용이 가능하다.

(ex) Select DISTINCT email from table;

(ex) SELECT class FROM courses GROUP BY(class) HAVING count(distinct student) >= 5;


-        GROUP BY

 : 데이터를 그루핑해서 결과를 가져오는 경우 사용. 내부적으로 중복값을 배제한채 정렬된 결과를 가져온다. 주로 HAVING과 같이 사용되며 그룹으로 묶어서 자체 정렬한다. 좀 더 정확히는 그룹의 대표값을 정렬해서 가져온다. 그렇기 때문에 모든 컬럼에 대해 단순 SELECT 하는 쿼리문에는 쓰기 적절치 않으며 테이블 내에서 데이터를 가공할 때 사용하기가 좋다. 예를 들어 accountType에 따라 해당하는 accountName의 row수를 그루핑 하고 싶다면 다음 쿼리를 사용해보자. Select accountType, COUNT(accountName) from accounts group by(accountType);

 

-      HAVING

 : HAVING은 GROUP BY 와 같이 쓰이는 구문으로 GROUP BY의 조건문이라 할 수 있다. 위의 쿼리에서 COUNT가 1개 이상인 내용만 쿼리를 하는데 다음처럼 사용 가능하다. SELECT accountType, COUNT(accountName) FROM accounts GROUP BY(accountType) HAVING COUNT(accountName) > 1; HAVING의 시점은 GROUPING이 끝난 이후이고 WHERE 절과 다르게 HAVING 절은 통계함수를 포함할 수 있다.

HAVING은 () 를 안 싸는 것이 좋다. 버전에 따라 오작동 위험이 있는듯하다 ;;


WHERE 구문과 같이 사용할 때, WHERE 구문이 먼저 적용되고 난 다음의 조건 결과에 대해 GROUP BY ~ HAVING 조건문이 걸린다. HAVING 조건문은 그룹화되어진 필드들에 대해 적용된다.

 

-      SubQuery 사용법

 : 복잡한 쿼리문을 만들 때 많이 사용하게 되는 구문이 서브쿼리문이다. 서브쿼리의 사용은 Nested Loop 를 돌기 때문에 사용에 주의하자.

(ex) SELECT accountInfo from accounts where accountName in (select accountName from accountNames);       //accountNames 테이블에 있는 이름에 대해서만 accountInfo를 조회하는 쿼리(Validation)

 


간단한 쿼리문 들이라 대부분 자주 쓰다보니 외워진 상태이지만, SQL에 막 입문하는 사람이거나 쿼리문에 익숙하지 않은 분들은 이 내용만 알게되어도 어느정도 복잡한 쿼리문도 다룰 수 있을 것이다.



+ Recent posts