데이터베이스 이용 시 핵심이 되는 처리가 바로 검색입니다. 데이터가 저장되어 있는 테이블에서 필요한 데이터를 뽑아내는 것인데, 질의(query)라던지 추출(retrieve)이라고 부릅니다. 이를 SELECT 구문이라고 부르고, 문자 그대로 선택한다는 것인데요. SELECT 구문은 2개의 부분으로 구성되어 있습니다.
6장 SELECT 구문
6.1 SELECT 구와 FROM 구
첫 번째는 SELECT 뒤에 나열되어 있는 부분으로, SELECT 구라고 부릅니다. 데이터베이스에서 검색할 때 반드시 입력되어야 하는 부분입니다. 테이블이 갖고 있는 필드라면 쉼표로 연결해 여러 개 쓸 수 있습니다.
두 번째 부분은 'FROM [테이블 이름]'으로 FROM 구라고 부르며, 데이터를 선택할 대상 테이블을 지정합니다. 반드시 입력되지 않아도 되고, 다만 테이블에서 데이터를 검색하는 경우는 반드시 입력해야 합니다.
6.2 WHERE 구
특정 조건에 맞는 일부의 레코드만 선택하고 싶을 때 사용합니다. 그리고 이때의 WHERE은 '어디?'를 나타내는 의문사가 아니라, '~라는 경우'를 나타내는 관계부사입니다.
1) WHERE 구의 다양한 조건 지정 : 다양한 조건 지정이 가능한데 이와 같습니다. [ =, <>, >=, >, <=, <]
2) WHERE 구는 거대한 벤다이어그램 : 특히 WHERE는 복잡한 조건을 연결할 때 자주 사용하는데, 벤다이어그램을 생각하면 좋습니다. 예로 AND, OR가 존재합니다.
3) IN으로 OR 조건을 간단하게 작성 : 때에 따라서는 OR 조건을 굉장히 많이 지정해야 할 때가 있습니다. 이때 IN이라는 도구가 있죠.
4) NULL -> 아무것도 아니라는 것은 무엇일까? : NULL 레코드를 선택할 때 'IS NULL'이라는 키워드를 사용해야 합니다. 반대는 'IS NOT NULL'이라는 키워드를 사용하면 되죠.
SELECT 구문의 기능은 절차 지향형 언어에서의 '함수'와 같다는 것을 알 수 있습니다. SELECT 구문도 테이블이라는 입력을 FROM 구로 받아, 특정 출력을 리턴한다는 점에서 같은 방식으로 작동합니다. SELECT 구문은 일종의 '읽기 전용' 함수라고 말할 수 있습니다.
SELECT 구문의 입력과 출력 자료형은 무엇일까요? '테이블(관계)'입니다. 입력 출력 모두 2차원 표라는 것이죠. 이러한 성질 때문에 관계가 닫혀있다는 의미로 폐쇄성이라고 부릅니다.
6.3 GROUP BY 구
테이블에서 단순하게 데이터를 선택하는 것뿐만 아니라 함께 또는 평균 등 집계 연산을 SQL 구문으로 할 수 있습니다. 쉽게 말해 '테이블을 홀 케이크처럼 다룬다'라고 할 수 있습니다. 칼과 같은 역할이죠.
- 그룹을 나누었을 때 장점 -> 잘라진 케이크 그룹을 그룹이라고 부릅니다. COUNT, SUM, AVG, MAX, MIN 같은 집계 함수가 있습니다. 또한 GROUP BY (); 로 사용이 가능한데, 키를 지정하지 않는다는 뜻입니다. 이럴 경우 생략도 가능하죠.
6.4 HAVING 구
WHERE 구가 '레코드'에 조건을 지정한다면, HAVING 구는 '집합'에 조건을 지정하는 기능이라고 할 수 있습니다.
6.5 ORDER BY 구
위에서 출력은 '딱히 정해진 규칙은 없다'라고 말할 수 있습니다. 모든 DBMS에서 SELECT 구문의 결과 순서를 보장하려면 명시적으로 순서를 지정해줘야 합니다. 'ASC', 'DESC' 키워드로 오름차순과 내림차순 정렬이 가능하죠.
6.6 뷰와 서브쿼리
DB를 사용하다 보면 SELECT 구문 중에서 자주 사용하는 것과 자주 사용하지 않는 것이 나옵니다. SELECT 구문은 텍스트 파일에 따로 자주 사용하는 것을 저장해 놓아도 좋을 것입니다. 하지만 사용자가 직접 텍스트 파일을 관리한다면 파일을 지워버리거나 덮어 씌워버릴 수 있죠. 이럴 때 데이터베이스 안에 SELECT 구문을 저장할 수 있다면 편리할텐데, 이 기능이 바로 뷰(View)입니다. DB 안에 데이터를 저장한다는 것은 테이블과 같지만, 테이블과 달리 데이터를 보유하지는 않습니다. 뷰는 'SELECT 구문'을 저장한 것뿐이랍니다. 일반 테이블처럼 SELECT 구문에서 사용할 수 있습니다.
익명 뷰 -> 뷰에서 데이터를 선택하는 SELECT 구문은, 실제로는 '추가적인 SELECT 구문'을 실행하는 중첩구조가 되는 것입니다. 뷰 대신에 FROM 구에 직접 SELECT 구문을 지정할 수도 있습니다. FROM 구에 직접 지정하는 SELECT 구문을 서브쿼리(subquery)라고 부릅니다.
서브쿼리를 사용한 편리한 조건 지정 -> 서브쿼리를 사용할 때 중요한 것을 한 가지 볼 텐데 WHERE 구의 조건에 서브쿼리를 사용하는 방법입니다. 공통되는 데이터와 공통되지 않은 데이터를 가진 2개의 테이블이 있다고 가정합니다. 이 두 테이블을 사용해 'a 테이블에서 b테이블에 있는 사람을 선택'하는 문장을 SQL로 만들어봅시다. 이런 처리를 매칭이라고 부릅니다.
이런 경우 편리하게 'IN으로 OR 조건을 간단하게 작성'에서 배웠던 IN입니다. 서브쿼리를 매개변수로도 사용가능하죠. IN과 서브쿼리를 함께 사용하는 구문은 데이터가 변경되어도 따로 수정할 필요가 없다는 점에서 편리합니다.
7장 조건 분기, 집합 연산, 윈도우 함수, 갱신
7.1 SQL과 조건분기
SQL은 코드를 절차적으로 기술하는 것이 아니므로 조건 분기를 '문장' 단위로 하지 않습니다. 바로 '식'입니다. 이런 식의 분기를 실현하는 기능이 CASE 식입니다.
1) CASE 식의 구문
'단순 CASE 식'과 '검색 CASE 식'이라는 두 종류가 있습니다. 다만 검색 CASE 식은 단순식의 기능을 모두 포함하고 있으므로 검색 CASE 식만 기억해도 충분합니다. WHEN 구의 평가식이라는 것은 '필드 = 값'처럼 조건을 지정하는 식을 말합니다.
2) CASE 식의 작동
CASE 식의 작동은 절차 지향형 프로그래밍 언어의 switch 조건문과 거의 비슷하죠. 절자 지향형 언어의 조건 분기 사이와 SQL 조건 분기 사이의 가장 큰 차이점은 바로 리턴값입니다. 절차 지향형 언어의 조건 분기는 문장을 실행하고 딱히 리턴하지 않습니다. 하지만 SQL 조건 분기는 특정한 값(상수)를 리턴합니다.
CASE 식의 강력한 점은 식이라는 것입니다. 식을 적을 수 있는 곳이면 어디든지 적을 수 있습니다. SELECT, GROUP BY, WHERE, HAVING, ORDER BY 구와 같은 어디에나 적을 수 있으므로 다양한 기법으로 활용할 수 있습니다.
7.2 SQL 집합의 연산
WHERE 구를 설명할 때 벤다이어그램을 사용한 집합 연산이라고 이야기했습니다. 이것은 예를 들었던 것인데, SQL에는 정말로 테이블을 사용해 집합 연산하는 기능이 있습니다.
1) UNION 합집합 구하기
WHERE 구에서는 합집합을 OR, 교집합을 AND가 담당했었습니다. 하지만 집합 연산에서는 다른데요. UNION이라는 연산자를 사용합니다. 문자 그대로 2개의 테이블을 하나의 테이블로 합친 결과가 나오죠. UNION은 합집합을 구할 때 중복된 레코드를 제거합니다. 만약 중복을 제거하고 싶지 않다면 'UNION ALL'처럼 ALL 옵션을 붙이면 된답니다.
2) INTERSECT로 교집합 구하기
AND에 해당하는 교집합을 구할 때 사용하는 연산자는 INTERSECT로 '교차'라는 의미입니다. 양쪽 테이블에 존재하는 레코드를 출력하고, 중복된 것이 있다면 해당 레코드는 제외됩니다.
3) EXCEPT로 차집합 구하기
이는 수식으로 나타내면 'Address - Address2'가 됩니다. EXCEPT에는 UNION과 INTERSECT에 없는 주의사항이 있습니다. UNION, INTERSECT는 어떤 테이블을 먼저 적든 그 순서와 상관없이 결과가 같지만 EXCEPT는 결과가 다릅니다. '교환 법칙이 성립하지 않는다' 때문이죠. 참고로 Oracle은 독자적으로 MINUS라는 이름의 연산자를 사용합니다.
7.3 윈도우 함수
윈도우 함수는 데이터를 가공하게 해준다는 점에서도 중요하지만, 성능과 큰 관계가 있습니다. 특징을 설명하면 '집약 기능이 없는 GROUP BY 구'입니다. GROUP BY 구는 자르기와 집약이라는 두 개의 기능으로 구분됩니다. 여기서 윈도우 함수는 자르기 기능만 있는 것이죠.
이를 'PARTITION BY'라는 구로 수행합니다. 차이점이 있다면 자른 후에 집약하지 않으므로 출력 결과의 레코드 수가 입력되는 레코드 수와 같다는 것입니다. 윈도우 함수의 기본적인 구문은 집약 함수 뒤에 OVER 구를 작성하고, 내부에 자를 키를 지정하는 PARTITION BY 또는 ORDER BY를 입력하는 것입니다. 작성하는 장소는 SELECT 구라고만 생각해도 문제없습니다.
윈도우 함수로 사용할 수 있는 함수로는 COUNT 또는 SUM 같은 일반 함수 이외에도, 전용 함수로 제공되는 RANK 또는 ROW_NUMBER 등 순서 함수가 있습니다. RANK 함수는 숫자가 같으면 같은 순위로 표시하고, 건너뛰어 다음 등수가 표시됩니다. 이런 건너뛰는 작업 없이 순위를 구하고 싶을 때는 DENSE_RANK 함수를 사용합니다. 윈도우 함수에는 이 이외에도 RANGE, ROWS 등 여러 세부 옵션을 지정할 수 있습니다.
7.4 트랜잭션과 갱신
SQL은 'Structured Query Language'의 약자입니다. 'Query'는 '질의'를 나타내며 좁은 뜻으로는 SELECT 구문을 나타냅니다. SQL은 데이터 검색을 중심으로 수행하기 위한 언어이고, 한마디로 데이터를 갱신하는 것은 부가적인 기능이라는 것입니다. 기본적으로 SQL의 갱신 작업은 대표적으로 3가지로 분류합니다. 삽입, 제거, 갱신.
1) INSERT로 데이터 삽입
RDB에서 데이터를 등록하는 단위는 레코드(행)입니다. 기본적인 등록 단위는 하나의 레코드씩이며, 이때 사용하는 것이 INSERT 구문인데, 문자 그대로 레코드를 '삽입'합니다. 레코드 INSERT시 필드 리스트와 값 리스트는 같은 순서로 대응하게 입력해야 합니다. 순서가 다르면 오류가 발생하거나 원하는 값이 들어가지 않으므로 주의해야 합니다.
문자열 자료형의 경우 작은따옴표로 감싸야하고, 숫자 자료형의 경우 감싸지 않습니다. 추가로 NULL을 삽입하는 경우 그대로 NULL을 입력합니다. 최근에는 여러 개의 레코드를 한 개의 INSERT 구문으로 삽입하는 기능(multi-row insert)을 지원하는 DBMS도 있습니다. 하지만 아직 지원하지 않는 DBMS도 있고, 오류가 발생했을 때 어떤 레코드가 문제인지 확인하기 어려운 단점도 있습니다. 해당 방식이 있다는 것을 기억해주면 됩니다.
2) DELETE로 데이터 제거
데이터를 삭제할 때는 하나의 레코드 단위가 아니라, 한 번에 여러 개의 레코드 단위로 처리하게 됩니다. 만약 부분적으로만 레코드를 제거하고 싶을 때는 SELECT 구문에서 사용했던 WHERE 구로 제거 대상을 선별합니다. DELETE 구문의 삭제 대상은 필드가 아니라 레코드이며, 만약 일부분의 레코드만 지우고 싶다면 UPDATE 구문을 사용하면 됩니다. DELETE 구문으로 모든 데이터를 삭제했다고, 테이블 자체가 사라지는 것이 아니라 테이블이라는 상자는 남아있으므로, 계속해서 INSERT 구문으로 새로운 데이터를 넣을 수도 있습니다.
3) UPDATE로 데이터 갱신
등록된 데이터를 이후에 변경할 수 있습니다. UPDATE 구문도 일부 레코드만 갱신하고 싶을 때 DELETE 구문처럼 WHERE 구로 필터링합니다. UPDATE 구문의 SET 구에 여러 필드를 입력하면, 한 번에 여러 개의 값을 변경할 수 있습니다.
마치며
- 간단하고, 직관적으로 작성할 수 있다는 것이 비절자형 언어 SQL 장점
- CASE 식은 조건 분기를 표현하는 중요한 도구, 포인트는 구문이 아니라 식을 바탕으로 한다는 것
- 쿼리는 입력과 출력 모두 테이블에 있는 것을 바탕으로 할 수 있으므로 유연함
- SQL은 GROUP BY, UNION, INTERSECT 등 집합 이론을 바탕으로 만들어진 연산이 많음.
- 윈도우 함수는 GROUP BY 구에서 집약 기능을 제외하고 자르는 기능만 남긴 것
'독서 > SQL 레벨업' 카테고리의 다른 글
5장 반복문 (0) | 2024.11.24 |
---|---|
4장 집약과 자르기 (0) | 2024.11.23 |
3장 SQL의 조건 분기 (0) | 2024.11.22 |
1장 DBMS 아키텍처 (0) | 2024.11.20 |