모던지 / SQL 개발자 / SQL 기본 및 활용 1강. 관계형 데이터베이스와 SELECT
SQL 기본 및 활용 1강. 관계형 데이터베이스와 SELECT
SQL은 무엇을 원하는지만 적는 언어입니다. 어떻게 찾을지는 적지 않습니다. 그 차이가 이 언어의 힘이고 동시에 함정입니다.
풀고 시작
문제 1. SELECT 문에서 실제로 가장 먼저 처리되는 절은 무엇일까요?
어디에서 가져올지가 정해져야 조건을 걸 수 있으므로 FROM이 가장 먼저 처리됩니다. 사람이 읽는 순서는 SELECT부터지만 데이터베이스가 처리하는 순서는 FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY입니다. 이 순서를 알아야 별칭을 어디서 쓸 수 있는지가 풀립니다.
집합을 다루는 언어
관계형 데이터베이스는 데이터를 테이블로 담습니다. 테이블은 행과 열로 이뤄지고, 행 하나가 1과목에서 말한 인스턴스이며 열 하나가 속성입니다. 여기서 중요한 성질은 테이블의 행에는 순서가 없다는 것입니다. 저장된 순서로 나올 것 같지만 보장되지 않습니다. 순서를 원하면 반드시 정렬을 지시해야 합니다.
SQL은 이 집합을 다루는 언어이고, 기능에 따라 다섯 갈래로 나뉩니다.
분류
하는 일
대표 명령
데이터 조작어 (DML)
데이터를 조회하고 바꿈
SELECT, INSERT, UPDATE, DELETE
데이터 정의어 (DDL)
구조를 만들고 바꿈
CREATE, ALTER, DROP, TRUNCATE, RENAME
데이터 제어어 (DCL)
권한을 주고 뺏음
GRANT, REVOKE
트랜잭션 제어어 (TCL)
변경을 확정하거나 되돌림
COMMIT, ROLLBACK, SAVEPOINT
SELECT를 DML로 분류하는 것에 의문이 들 수 있는데, 데이터를 다루는 명령이라는 뜻에서 그렇게 봅니다. 자료를 바꾸지 않는다는 점을 강조할 때는 따로 질의어로 부르기도 합니다. 그리고 DDL은 대체로 자동 커밋된다는 점이 시험에서 갈리는 자리입니다. 테이블을 지운 뒤 되돌리려 해도 이미 확정되어 있습니다.
SELECT 문의 뼈대
가장 단순한 형태는 무엇을, 어디에서 가져올지 두 줄입니다.
SELECT 사원명, 급여
FROM 사원;
여기에 조건과 묶음과 정렬이 붙습니다. 작성 순서는 정해져 있습니다. SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY입니다. 그런데 처리 순서는 다릅니다. FROM으로 대상을 정하고, WHERE로 행을 걸러 내고, GROUP BY로 묶고, HAVING으로 묶음을 걸러 내고, SELECT로 열을 고르고, 마지막에 ORDER BY로 줄을 세웁니다.
이 순서를 알면 오래 헷갈렸던 것이 한 번에 풀립니다. SELECT에서 붙인 별칭을 WHERE에서 쓸 수 없는 이유는 WHERE가 SELECT보다 먼저 처리되기 때문입니다. 반대로 ORDER BY에서는 별칭을 쓸 수 있습니다. SELECT 다음에 처리되니까요.
컬럼에 산술식을 쓸 수도 있습니다. 급여 * 12 처럼요. 이때 결과 컬럼 이름이 식 그대로 나오니 별칭(alias)을 붙이는 편이 낫습니다. AS는 생략할 수 있고, 이름에 공백이나 특수문자를 쓰려면 이중 인용부호로 감쌉니다. 한글 별칭도 이중 인용부호 없이 쓰는 경우가 많지만 제품마다 다릅니다.
중복 제거와 문자열 붙이기
같은 값이 여러 행에 있을 때 한 번만 보고 싶다면 DISTINCT를 씁니다. SELECT DISTINCT 부서코드 FROM 사원 이 그것이죠. 반대로 아무것도 적지 않으면 기본값은 ALL이고, 중복이 그대로 나옵니다. DISTINCT를 여러 컬럼에 쓰면 컬럼 조합 단위로 중복을 없앤다는 점을 기억해 두세요. 컬럼마다 따로 중복을 없애는 것이 아닙니다.
문자열을 이어 붙일 때는 두 가지 길이 있습니다. 표준에 가까운 CONCAT 함수와, 수직선 기호 두 개를 쓰는 연결 연산자입니다. CONCAT은 제품에 따라 인자를 두 개만 받는 경우가 있어 셋 이상을 이을 때는 중첩해서 씁니다. 그리고 NULL과 문자열을 이으면 결과가 어떻게 되는지가 제품마다 다릅니다. 일부 제품은 NULL을 빈 문자열처럼 취급해 나머지를 그대로 이어 주고, 표준을 엄격히 따르는 쪽은 결과 전체를 NULL로 만듭니다. 시험에서는 각 제품의 동작을 묻기보다 NULL이 개입하면 결과가 달라진다는 사실을 묻습니다.
주석과 세미콜론, 그리고 사소하지만 자주 틀리는 것들
한 줄 주석은 하이픈 두 개로 시작하고, 여러 줄 주석은 슬래시와 별표로 여닫습니다. 명령의 끝은 세미콜론으로 표시합니다.
그리고 시험에서 은근히 자주 나오는 사실들이 있습니다. SQL의 예약어는 대소문자를 구분하지 않습니다. SELECT와 select가 같습니다. 그런데 문자열 값은 대소문자를 구분합니다. 이름을 조건으로 걸 때 대소문자가 다르면 걸리지 않죠. 문자열은 단일 인용부호로 감싸고, 이중 인용부호는 식별자를 감싸는 데 씁니다. 이 둘을 바꿔 쓰면 컬럼 이름을 찾을 수 없다는 오류가 납니다.
다음 강에서는 이 SELECT에 조건을 거는 WHERE 절을 봅니다. 조건 하나를 잘못 쓰면 결과가 아니라 결과의 개수가 달라지므로, 연산자마다 성질을 정확히 알아 둘 필요가 있습니다.
인출 문제
문제 1. SELECT 절에서 붙인 별칭을 사용할 수 있는 절은?
처리 순서상 SELECT보다 뒤에 오는 절에서만 별칭을 알아볼 수 있고, 그 절은 ORDER BY입니다. WHERE와 GROUP BY와 HAVING은 모두 SELECT보다 먼저 처리되므로 별칭을 인식하지 못합니다.
문제 2. SQL 명령의 분류가 잘못 짝지어진 것은?
ROLLBACK은 변경을 되돌리는 명령이므로 트랜잭션 제어어입니다. 권한을 주고 뺏는 GRANT와 REVOKE가 데이터 제어어이고, 구조를 지우면서 자동 커밋되는 TRUNCATE는 데이터 정의어로 분류합니다.
문제 3. DISTINCT를 두 개의 컬럼에 함께 사용했을 때의 동작으로 옳은 것은?
DISTINCT는 선택한 컬럼들의 조합 하나를 한 건으로 보고 중복을 없앱니다. 컬럼마다 따로 처리한다면 서로 짝이 맞지 않는 값들이 한 행에 섞이게 되므로 애초에 성립하지 않습니다.
문제 4. 다음 중 옳은 설명은?
예약어는 대소문자를 가리지 않지만 데이터로 들어 있는 문자열은 가립니다. 문자열은 단일 인용부호로 감싸고 이중 인용부호는 식별자용이며, 행의 순서는 정렬을 지시하지 않으면 보장되지 않습니다.
더 풀기
출제기준의 세세항목을 따라 이 강의 범위에서 새로 낸 문제입니다. 모의고사도 여기에서 뽑습니다.
묶음 1
문제 1. 관계형 데이터베이스에서 릴레이션을 가장 잘 설명한 것은?
릴레이션은 관계라는 뜻이지만 여기서는 테이블에 해당하는 집합을 가리킵니다. 테이블 사이의 연결은 관계 또는 조인이라는 다른 말로 부릅니다.
문제 2. SQL이 집합을 다루는 언어라는 말의 뜻으로 가장 알맞은 것은?
SQL은 무엇을 원하는지 적으면 어떻게 찾을지는 데이터베이스가 정합니다. 그래서 한 건씩 처리하는 사고에서 벗어나야 잘 쓸 수 있습니다.
문제 3. SQL 명령을 분류할 때 SELECT는 어디에 속하나요?
표기에 따라 SELECT를 DML에 포함시키기도 하고 조회만 따로 떼어 DQL이라 부르기도 합니다. 어느 쪽이든 구조를 바꾸는 DDL이나 권한을 다루는 DCL과는 다릅니다.
문제 4. SELECT 문에서 논리적으로 가장 먼저 처리되는 절은?
작성 순서는 SELECT가 먼저지만 처리 순서는 FROM으로 시작합니다. 대상을 정하고 조건을 걸고 묶고 걸러 낸 뒤 마지막에 무엇을 보여 줄지 고릅니다.
문제 5. SELECT 문의 논리적 처리 순서를 바르게 나열한 것은?
FROM에서 대상을 정하고 WHERE로 행을 거른 뒤 GROUP BY로 묶고 HAVING으로 그룹을 거릅니다. SELECT는 그다음이고 ORDER BY가 가장 마지막입니다.
문제 6. SELECT 절에서 붙인 별칭을 WHERE 절에서 쓸 수 없는 이유로 가장 알맞은 것은?
처리 순서를 알면 자연스럽게 이해됩니다. 반대로 ORDER BY는 SELECT 뒤에 처리되므로 별칭을 쓸 수 있습니다.
문제 7. DISTINCT를 쓰면 어떤 기준으로 중복이 제거되나요?
DISTINCT는 나열한 컬럼 전부를 한 덩어리로 보고 같은 조합을 하나로 줄입니다. 컬럼을 하나 더 넣으면 중복이 덜 제거되는 이유가 여기 있습니다.
문제 8. 부서코드가 십과 십과 이십인 세 행에서 부서코드에 DISTINCT를 적용하면 결과 행 수는?
같은 값 십이 하나로 줄어 십과 이십 두 행이 남습니다.
문제 9. 부서코드가 십과 십과 이십이고 직급이 각각 대리와 과장과 대리인 세 행에서 부서코드와 직급 조합에 DISTINCT를 적용하면 결과 행 수는?
조합으로 보면 십과 대리, 십과 과장, 이십과 대리로 모두 다릅니다. 그래서 세 행이 그대로 남습니다.
문제 10. 조회 결과의 컬럼에 별칭을 붙일 때 공백이나 특수문자가 들어가야 한다면 어떻게 해야 하나요?
표준에서는 식별자를 큰따옴표로 감쌉니다. 작은따옴표는 문자 상수를 나타내는 용도라 별칭에는 쓰지 않습니다.
묶음 2
문제 1. 문자열을 이어 붙이는 표준 연산자는?
표준 SQL에서 문자열 연결은 세로 막대 두 개입니다. 제품에 따라 CONCAT 함수를 함께 제공하기도 합니다.
문제 2. 문자열 연결에서 한쪽이 NULL이면 표준적으로 어떤 결과가 나오나요?
표준에서는 NULL이 섞이면 결과도 NULL입니다. 다만 일부 제품은 NULL을 빈 문자열처럼 다루므로 이식할 때 주의해야 합니다.
문제 3. 숫자 컬럼과 문자 컬럼을 함께 조회할 때 사이에 구분자를 넣어 하나의 값으로 보이게 하려면 어떤 기능이 필요한가요?
숫자를 문자와 이으려면 먼저 문자로 바꾸어야 합니다. 많은 제품이 묵시적으로 처리하지만 명시적으로 바꾸는 편이 안전합니다.
문제 4. SQL에서 한 줄 주석을 나타내는 표기는?
한 줄 주석은 하이픈 두 개, 여러 줄 주석은 사선과 별표로 감쌉니다.
문제 5. 문장 끝의 세미콜론이 하는 일로 가장 알맞은 것은?
세미콜론은 문장 구분자입니다. 트랜잭션 종료는 COMMIT이나 ROLLBACK이 담당합니다.
문제 6. 문자 상수를 표현할 때 쓰는 따옴표는?
문자 상수는 작은따옴표로 감쌉니다. 큰따옴표는 컬럼 이름 같은 식별자를 감쌀 때 씁니다.
문제 7. 사원 이름이 오브라이언처럼 작은따옴표를 포함할 때 문자 상수로 표현하는 표준 방법은?
표준에서는 작은따옴표를 두 번 써서 하나의 따옴표를 나타냅니다. 역슬래시 이스케이프는 일부 제품의 확장입니다.
문제 8. 테이블 별칭을 붙였을 때 그 뒤부터 원래 테이블 이름을 쓸 수 없는 이유로 가장 알맞은 것은?
별칭은 대체가 아니라 그 범위 안에서의 이름 자체입니다. 그래서 원래 이름으로 참조하면 알 수 없는 이름이 됩니다.
문제 9. 여러 테이블을 조회할 때 컬럼 앞에 테이블 별칭을 붙이는 습관이 좋은 이유로 가장 알맞은 것은?
지금은 모호하지 않아도 나중에 컬럼이 추가되면 갑자기 모호해집니다. 별칭을 붙여 두면 그 변화에 영향을 받지 않습니다.
문제 10. SELECT 절에 별표를 쓰는 것을 실무에서 권하지 않는 이유로 가장 알맞은 것은?
별표는 편하지만 읽는 양이 늘고 컬럼 추가에 취약합니다. 필요한 컬럼을 적어 두면 의도가 문장에 남습니다.
묶음 3
문제 1. 다음 중 SQL 문장으로 실행했을 때 결과가 항상 한 행인 것은?
그룹 기준 없이 집계 함수만 쓰면 테이블 전체가 하나의 그룹이 되어 결과가 한 행입니다. 대상 행이 하나도 없어도 한 행이 나옵니다.
문제 2. 사원 테이블에 행이 하나도 없을 때 전체 행 수를 세면 결과는?
개수를 세는 함수는 대상이 없어도 영을 돌려줍니다. 반면 합계나 평균은 NULL이 나옵니다.
문제 3. 사원 테이블에 행이 하나도 없을 때 급여의 합계를 구하면 결과는?
더할 값이 하나도 없으므로 합계는 알 수 없는 상태인 NULL이 됩니다. 영으로 보고 싶다면 NULL 대체 함수를 써야 합니다.
문제 4. 관계형 데이터베이스에서 행의 순서에 대해 옳은 설명은?
순서가 우연히 맞아 보일 수는 있지만 보장되지 않습니다. 순서가 필요하면 반드시 명시해야 합니다.
문제 5. 다음 중 DDL에 속하는 명령은?
구조를 다루는 CREATE와 ALTER와 DROP이 DDL입니다. INSERT와 UPDATE는 DML, COMMIT은 TCL입니다.
문제 6. 다음 중 DCL에 속하는 명령은?
권한을 주고 뺏는 GRANT와 REVOKE가 DCL입니다. TRUNCATE는 구조를 건드리는 DDL로 분류합니다.
문제 7. 사원 테이블에서 서로 다른 부서코드가 몇 개인지 구하려면 어떤 조합이 필요한가요?
개수 함수 안에 DISTINCT를 넣으면 서로 다른 값의 수가 나옵니다. 그룹으로 묶어 그 결과의 행 수를 세는 방법도 있습니다.
문제 8. 부서코드가 십과 십과 이십과 NULL인 네 행에서 서로 다른 부서코드의 개수를 세면?
중복을 없애면 십과 이십이 남고 NULL은 개수 함수에서 제외되므로 둘입니다.
문제 9. 조회 결과에 고정된 문자열을 한 컬럼처럼 붙여 보여 주고 싶다면?
SELECT 절에는 컬럼뿐 아니라 상수와 식도 올 수 있습니다. 상수는 모든 행에 같은 값으로 나타납니다.
문제 10. SQL 문장을 작성할 때 대소문자에 대해 옳은 설명은?
명령어는 대소문자를 가리지 않는 것이 일반적이지만 저장된 문자 값은 대개 구분됩니다. 그래서 조건을 걸 때 값의 대소문자를 맞추거나 함수로 통일해야 합니다.