SQLD를 공부하면서, SQL의 basic concept와 주의하거나 알면 좋은 지점들에 대해서 정리해보았습니다.
SQL(Structured Query Language)은 관계형 데이터베이스 관리 시스템(RDBMS)에서 데이터를 관리하고 조작하기 위해 사용되는 표준 언어입니다. SQL을 사용하면 데이터베이스에 저장된 데이터를 삽입, 수정, 삭제 및 조회할 수 있습니다. SQL은 강력한 데이터 조작 기능과 함께 데이터베이스 스키마 생성 및 변경을 위한 명령도 제공합니다. SQL의 주요 구성 요소로는 DDL(데이터 정의 언어)
, DML(데이터 조작 언어)
, DQL(데이터 질의 언어)
등이 있습니다.
--
: 인라인 한 줄짜리 주석/* ... */
: 여러 줄에 걸쳐 사용 가능한 주석User
vs Users
_
vs CamelCasing 예) user_time
vs UserTime
Pandas가 등장할 당시에는, '전반적인 데이터 처리 트렌드가 SQL에서 Pandas로 넘어오겠다'라고 생각하는 개발자들도 존재했다고 한다. 하지만, SQL과 달리 코드 관계자가 아닌 인원이 코드를 보고 한눈에 어떤 의미인지를 모른다는 치명적인 단점이 존재하여, 여전히 SQL은 데이터 조작 언어로서 입지를 공공히 하고 있다.
물론 설계 목적 자체가 다르기 때문에 비교하는 것이 무의미할 수 있지만, 데이터를 다룬다는 큰 범주안에서 유사한 역할을 담당한다고 볼 수 있기에 같이 설명을 드리려고 합니다.
보통 SQL은 디스크 기반의 대규모 데이터베이스에서 효율적으로 작동하고, 데이터베이스 서버에서 실행됩니다. 반면에 Pandas는 데이터프레임 형태로 메모리에 데이터를 로드하여 빠르고 유연한 데이터 조작을 가능하게 합니다. 사실, Pandas의 메모리 할당 방식은 대규모 데이터를 다루기 어렵기 때문에, 이 때 유사한 용도로 PySpark가 많이 쓰입니다. 대규모 데이터에 대한 명확한 기준은 없지만, 경험 상 10GB가 넘어가는 데이터를 처리할 때는 PySpark를 사용하는 것이 유리한 것 같습니다.
CREATE TABLE ... AS SELECT ...
을 통해 서머리 테이블을 생성할 수 있습니다.CREATE TABLE
→ INSERT
→ SELECT
DROP TABLE ...;
:DROP TABLE IF EXISTS ...;
사용을 권장합니다.DELETE FROM
은 조건에 맞는 레코드들을 삭제합니다(테이블 자체는 유지).ALTER TABLE 테이블이름 ADD COLUMN 필드이름 필드타입;
ALTER TABLE 테이블이름 RENAME 현재필드이름 TO 새필드이름;
ALTER TABLE 테이블이름 DROP COLUMN 필드이름;
ALTER TABLE 현재테이블이름 RENAME TO 새테이블이름;
SELECT, FROM, WHERE 절은 너무 기초적인 문법이기에 설명에서 제외
WHERE channel IN ('Google', 'Youtube')
:WHERE channel = 'Google' OR channel = 'Youtube'
WHERE channel LIKE 'G%'
→ 'G*'
WHERE channel LIKE '%o%'
→ '*o*'
NOT LIKE
또는 NOT ILIKE
LEFT(str, N)
REPLACE(str, exp1, exp2)
UPPER(str)
LOWER(str)
LEN(str)
LPAD
, RPAD
SUBSTRING
INSERT INTO table SELECT * FROM ...
:CREATE TABLE table AS SELECT
보다 낫습니다.--- mau 계산 sql예시
SELECT TO_CHAR(A.TS, 'YYYY-MM') AS month,
COUNT(DISTINCT B.userid) AS mau
FROM raw_data.session_timestamp A
JOIN raw_data.user_session_channel B ON A.sessionid = B.sessionid
GROUP BY 1
ORDER BY 1 DESC;
ORDER BY 1 DESC;
→ NULL이 가장 앞에 위치ORDER BY 1 DESC NULLS LAST;
→ NULL이 맨 뒤로 이동GROUP BY 1
== GROUP BY month
== GROUP BY TO_CHAR(A.ts, 'YYYY-MM')
cast
또는 ::
연산자 사용channel::int
(본 예시는 PostgreSQL기반의 Redshift에 해당, SQL마다 다를 수 있음)cast(channel as int)
convert_timezone
convert_timezone('America/Los_Angeles', ts)
SELECT pg_timezone_names()
date
, truncate
date_trunc
extract
또는 date_part
: 날짜, 시간에서 특정 부분의 값을 추출datediff
, dateadd
, get_current...
TO_CHAR(A.TS, 'YYYY-MM') AS month
은 아래와 같이 사용해도 같은 output을 도출LEFT(A.ts, 7)
DATE_TRUNC('month', A.ts)
SUBSTRING(A.TS, 1, 7)
값이 존재하지 않음을 의미하고, 0과 비어있는 문자열과는 다르다는 점을 인지해야 한다.
IS NULL
, IS NOT NULL
형식으로 사용IS TRUE
, IS FALSE
형식으로 비교COALESCE
NULLIF
SELECT 10 / NULL; -- 결과: NULL
SELECT 10 / 0; -- 결과: 오류 (Division by zero)
… | … | value |
---|---|---|
… | … | NULL |
… | … | 1 |
… | … | 1 |
… | … | 0 |
… | … | 0 |
… | … | 4 |
… | … | 3 |
COUNT(0) FROM Table = 7
COUNT(value) FROM Table = 6
COUNT(DISTINCT value) FROM Table = 4
세부적으로 들어가면 사실 최종적인 실행순서는 보통 쿼리 옵티마이져에 의해서 결정된다. 다만, 기본적으로 아래 사진과 같이 이해하고 있다면 SQL문을 작성할 때 크게 도움이 된다.