구글 빅쿼리에서 사용하는 대부분의 문법은 일반 RDBMS SQL과 매우 유사합니다. 이번 글에서는 이러한 SQL의 기초적인 사용법에 대해서 정리를 하도록 하겠습니다. 갑자기 SQL을 정리하게 된 이유는 회사에서 이를 정리해야 하는 일이 있었기 때문입니다 😂
SELECT
문은 데이터를 검색하고 추출할 때 사용하는 가장 기본적인 구문임SELECT [열1], [열2], ... [열n] FROM [테이블 이름] WHERE [조건]
SELECT
: 가져올 열(column)을 지정합니다. *을 사용하면 모든 열을 선택합니다.FROM
: 데이터를 가져올 테이블 이름을 지정합니다.WHERE
: 가져올 데이터의 조건을 지정합니다. WHERE절은 선택적으로 사용할 수 있습니다.
-- 임시 테이블 생성
CREATE TABLE #MYTABLE (
id INT,
name VARCHAR(50),
age INT,
gender CHAR(1)
);
INSERT INTO #MYTABLE (id, name, age, gender)
VALUES (1, 'John', 25, 'M')
INSERT INTO #MYTABLE (id, name, age, gender)
VALUES (2, 'Jane', 30, 'F')
INSERT INTO #MYTABLE (id, name, age, gender)
VALUES (3, 'Sam', 27, 'M')
INSERT INTO #MYTABLE (id, name, age, gender)
VALUES (4, 'Jenny', 23, 'F');
INSERT INTO #MYTABLE (id, name, age, gender)
VALUES (5, 'Robin', 28, 'M')
CREATE TABLE #MYSALARY (
id INT,
salary INT
);
INSERT INTO #MYSALARY (id, salary)
VALUES (1, 50000)
INSERT INTO #MYSALARY (id, salary)
VALUES (2, 60000)
INSERT INTO #MYSALARY (id, salary)
VALUES (3, 55000)
INSERT INTO #MYSALARY (id, salary)
VALUES (4, 45000);
SELECT NAME, AGE
FROM #MYTABLE
---
SELECT NAME, AGE
FROM #MYTABLE
WHERE GENDER = 'M'
IN
연산자는 WHERE절에서 여러 개의 값을 비교할 때 사용됨SELECT * FROM employees WHERE department IN ('Sales', 'Marketing')
SELECT * FROM employees WHERE department NOT IN ('Sales', 'Marketing')
LIKE
연산자는 WHERE절에서 문자열 비교를 할 때 사용함SELECT * FROM employees WHERE employee_name LIKE '%an%'
Ian
, ~~~an~~~~
)SELECT TOP 5 * FROM item WHERE item_nm LIKE N'%생수%'
생수
란 단어가 포함되어 있는 데이터를 반환함DISTINCT
는 중복된 값을 제거하여 유일한 값을 반환하는 키워드임. 쿼리 결과에서 중복된 값을 제거하고 한 번만 나타나는 값을 반환함SELECT DISTINCT NAME FROM #MYTABLE
DISTINCT를 사용하면 쿼리 성능에 문제가 있을 수 있음, 지나치게 쿼리 수행시간이 길어질 수 있음
SELECT문 안에서 사용되는 컬럼에만 영향을 미침. 다른 컬럼에 중복이 있어도 이는 무시함
NULL값 고려 안 함. NULL값이 중복된 경우에도 하나의 값으로 취급되지 않음
JOIN과 같이 사용하는 경우 결과를 확인해야 함
TOP
은 쿼리 결과에서 상위 N개의 값을 반환하는 키워드임. 비슷한 키워드로 LIMIT가 있음 (빅쿼리에서는 LIMIT
사용)SELECT TOP 5 * FROM item WHERE item_nm LIKE N'%생수%'
ORDER BY
임ORDER BY
는 SELECT 쿼리 결과의 정렬 순서를 지정하는 키워드임SELECT NAME FROM #MYTABLE ORDER BY AGE DESC
#MYTABLE
에서 AGE
가 높은 순서대로 NAME
을 반환함ORDER BY
뒤에 붙은 컬럼명으로 데이터를 정렬하여 반환하며 디폴트는 오름차순, 컬럼명 뒤에 DESC가 붙으면 내림차순임SELECT NAME, AGE FROM #MYTABLE ORDER BY 2 DESC
JOIN
은 두 개 이상의 테이블을 연결하여 데이터를 검색하는 방법임INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN
등이 있음SELECT *
FROM 테이블1
JOIN 테이블2
ON 테이블1.컬럼1 = 테이블2.컬럼2
SELECT *
FROM 테이블1
LEFT OUTER JOIN 테이블2
ON 테이블1.컬럼1 = 테이블2.컬럼2
SELECT *
FROM 테이블1
RIGHT OUTER JOIN 테이블2
ON 테이블1.컬럼1 = 테이블2.컬럼2
CROSS JOIN
은 두 테이블의 모든 가능한 조합을 반환함SELECT *
FROM table1
CROSS JOIN table2
SELF JOIN
은 하나의 테이블 내에서 자체적으로 조인하는 것을 의미함SELECT a.column1, b.column2
FROM table a
JOIN table b ON a.column3 = b.column3
COUNT, SUM, AVG, MAX, MIN
등이 존재함COUNT
함수는 지정한 열에서 NULL 값을 제외한 행의 개수를 반환함SELECT COUNT(*) FROM 테이블
SUM
함수는 지정한 열의 모든 행의 값을 더한 총합을 반환함SELECT SUM(SALES) FROM 테이블
AVG
함수는 지정한 열의 모든 행의 값을 평균화한 결과를 반환함SELECT AVG(SALES) FROM 테이블
MAX
함수는 지정한 열의 모든 행 중 가장 큰 값을 반환함SELECT MAX(SALES) FROM 테이블
MIN
함수는 지정한 열의 모든 행 중 가장 작은 값을 반환함SELECT MIN(SALES) FROM 테이블
GROUP BY
절과 함께 사용하여 특정 열 기준으로 데이터를 그룹화한 후 그룹 별로 결과를 반환할 수 있음SELECT id, COUNT(order)
FROM ord
GROUP BY id
HAVING
절은 WHERE 절과 비슷하지만, GROUP BY 절에 의해 그룹화된 결과 집합에서 행을 필터링하는 역할을 함SELECT title, AVG(salary) as avg_salary
FROM employees_table
WHERE title = 'manager'
GROUP BY title
HAVING AVG(salary) > 50000
SELECT column1, column2, column3
FROM table1
WHERE column1 IN (SELECT column1 FROM table2 WHERE column2 = 'value')
--------------------
SELECT column1, column2, column3
FROM (SELECT column1, column2, column3 FROM table1 WHERE column1 = 'value') AS subquery
--------------------
SELECT column1, column2, (SELECT COUNT(column3) FROM table2 WHERE column2 = 'value') AS count
FROM table1
SELECT column1, column2, column3
FROM table1
WHERE EXISTS (SELECT * FROM table2 WHERE table1.column1 = table2.column1)
--------------------
SELECT column1, column2, column3
SELECT column1, column2, column3
FROM table1
WHERE column1 = ANY (SELECT column1 FROM table2 WHERE column2 = 'value')
--------------------
SELECT column1, column2, column3
FROM table1
WHERE column1 = ALL (SELECT column1 FROM table2 WHERE column2 = 'value')
EXIST, ANY, ALL
의 사용 예시임. EXIST
는 서브쿼리가 반환하는 결과가 존재하는지 여부를 검사함. 서브쿼리에서 반환된 값이 존재하면, 참을 반환함ANY
는 서브쿼리에서 반환된 값 중 하나라도 메인쿼리의 조건식과 일치하면 참을 반환함ALL
은 서브쿼리에서 반환된 모든 값이 메인쿼리의 조건식과 일치하면 참을 반환함서브쿼리는 작은 데이터 집합을 추출할 때 사용함. 반면 JOIN은 더 큰 데이터 집합을 추출하는 데 사용함
서브쿼리는 다음과 같을 때 사용하기에 더 적합함
- 메인 쿼리와 별개로 작은 데이터 집합을 추출해야 할 때
- 메인 쿼리의 실행 결과에 영향을 미치지 않으면서 데이터를 추출해야 할 때
- 복잡한 조건식을 사용해야 할 때
JOIN은 다음과 같을 때 사용하기에 적합함
- 두 개 이상의 테이블을 조인해서 더 큰 데이터 집합을 추출해야 할 때
- 테이블 간 관계를 명확하게 이해하고 있어야 할 때
- 여러 개의 조건식이 필요한 경우
CTE
는 Common Table Expression, 즉 공통 테이블 표현식을 의미함WITH cte AS (
SELECT column1, column2, ...
FROM table_name
WHERE condition
)
SELECT *
FROM cte;
-- 1. CTE
WITH sales_info AS (
SELECT
customer_id,
SUM(sale_amount) AS total_sales
FROM sales
GROUP BY customer_id
)
SELECT
customer_id,
total_sales
FROM sales_info
WHERE total_sales > 10000;
-- 2. Subquery
SELECT
customer_id,
total_sales
FROM (
SELECT
customer_id,
SUM(sale_amount) AS total_sales
FROM sales
GROUP BY customer_id
) AS sales_info
WHERE total_sales > 10000;
OVER()
절을 사용하여 정의됨<윈도우 함수> OVER ([PARTITION BY <열>]
[ORDER BY <열> [ASC|DESC], ...])
ROW_NUMBER()
: 각 행에 대해 일련 번호를 지정함RANK()
: 순위를 지정함. 동일한 값을 가진 행은 같은 순위를 갖게 됨DENSE_RANK()
: 순위를 지정함. 동일한 값을 가진 행은 같은 순위를 갖게 되지만, 순위 사이에 빈 순위는 없음.NTILE()
: 결과 집합을 동일한 크기의 그룹으로 분할함.LAG()
: 이전 행의 값을 가져옴.LEAD()
: 다음 행의 값을 가져옴.FIRST_VALUE()
: 윈도우 내 첫 번째 행의 값을 반환함.LAST_VALUE()
: 윈도우 내 마지막 행의 값을 반환함.SELECT name, score,
ROW_NUMBER() OVER(ORDER BY score DESC) AS rank,
RANK() OVER(ORDER BY score DESC) AS rank2,
DENSE_RANK() OVER(ORDER BY score DESC) AS rank3,
NTILE(3) OVER(ORDER BY score DESC) AS group,
LAG(score, 1) OVER(ORDER BY score DESC) AS prev_score,
LEAD(score, 1) OVER(ORDER BY score DESC) AS next_score,
FIRST_VALUE(score) OVER(ORDER BY score DESC) AS first_score,
LAST_VALUE(score) OVER(ORDER BY score DESC) AS last_score
FROM students
SELECT
ROW_NUMBER() OVER (ORDER BY Salary DESC) AS RowNum,
FirstName,
LastName,
Salary
FROM
Employees
SELECT
RANK() OVER (ORDER BY Sales DESC) AS Rank,
FirstName,
LastName,
Sales
FROM
Salespeople
SELECT
DENSE_RANK() OVER (ORDER BY Sales DESC) AS DenseRank,
FirstName,
LastName,
Sales
FROM
Salespeople
SELECT
department,
name,
salary,
AVG(salary) OVER(PARTITION BY department) as avg_salary_per_dept
FROM employees;