본 시리즈에서는 데이터베이스의 개념을 정리하고 필요시 실습을 진행합니다.
Ubuntu-24.04
)10.11.8-MariaDB
)2024.2.2
)correto-21
)Ultimate Edition
)world database
CRUD는 데이터의 생성(Create), 조회(Read), 수정(Update), 삭제(Delete)를 의미하며, 대부분의 애플리케이션이 데이터를 관리하는 기본적인 네 가지 작업입니다.
SQL의 CRUD는 다음과 같이 데이터베이스에서 데이터를 관리하는 네 가지 주요 작업을 포함합니다.
INSERT
users
테이블에 추가INSERT INTO users (user_id, name, email) VALUES (1, 'Alice', 'alice@example.com');
SELECT
users
테이블에서 모든 사용자 정보 조회SELECT * FROM users;
UPDATE
UPDATE users SET email = 'new_email@example.com' WHERE user_id = 1;
DELETE
users
테이블에서 삭제DELETE FROM users WHERE user_id = 1;
이와 같이, SQL에서의 CRUD는 데이터베이스를 조작하고 관리하기 위한 기본적인 명령어들로 구성됩니다.
웹 애플리케이션에서 CRUD 작업은 일반적으로 HTTP 메서드와 매칭되어 사용됩니다.
SQL의 CRUD 작업과 HTTP 메서드 간의 대응 관계는 다음과 같습니다.
작업 | SQL 명령어 | HTTP 메서드 | 설명 |
---|---|---|---|
Create | INSERT | POST | 새로운 리소스를 생성 |
Read | SELECT | GET | 기존 데이터를 조회 |
Update | UPDATE | PUT / PATCH | 기존 데이터를 수정 |
Delete | DELETE | DELETE | 기존 데이터를 삭제 |
이와 같이, SQL의 CRUD 작업과 HTTP 메서드는 데이터의 생성, 조회, 수정, 삭제라는 기본적인 목적을 공유하며, 웹 애플리케이션에서 데이터베이스와의 상호작용을 이해하는 데 중요한 개념입니다.
참고: CRUD와 HTTP 메서드의 관계에 대한 자세한 내용은 네트워크 파트에서 다룰 예정입니다.
Alias(AS)와 WildCard(*)는 SQL 쿼리
에서 자주 사용되는 기능으로, 데이터를 더 쉽게 조회하고 조작할 수 있도록 도와줍니다.
Alias(AS)는 열(Column)이나 테이블에 별칭(별명)을 부여하는 기능으로, 쿼리 결과를 더 읽기 쉽게 하거나, 복잡한 쿼리에서 특정 열이나 테이블을 간단하게 표현할 때 유용합니다.
AS
키워드를 사용하여 별칭을 설정하며, 별칭은 주로 보고서나 데이터 시각화 시 가독성을 높이는 데 사용됩니다.-- 열에 별칭 사용
SELECT name AS 'Name', salary AS 'Annual Salary' FROM employees;
-- 테이블에 별칭 사용
SELECT e.name, d.department_name
FROM employees AS e
JOIN departments AS d ON e.department_id = d.department_id;
참고:
AS
키워드는 생략 가능하지만, 가독성을 위해 사용하는 것이 좋습니다.
Wildcard(*)는 모든 열을 선택할 때 사용되는 기호로, *
를 사용하여 테이블의 모든 열을 한번에 조회할 수 있습니다.
-- 모든 열 조회
SELECT * FROM employees;
주의사항:
*
를 사용하여 불필요한 데이터를 조회하는 것은 성능에 영향을 미칠 수 있습니다. 필요한 열만 선택하여 데이터를 조회하는 것이 일반적으로는 더 좋습니다.
DML(Data Manipulation Language)은 SQL
에서 데이터베이스에 저장된 데이터를 조작하는 명령어로 구성된 언어입니다.
SELECT, INSERT, UPDATE, DELETE
가 있습니다.이번 파트부터는 MySQL 예시 데이터를 활용해볼 것입니다.
- 다운로드 링크 : https://dev.mysql.com/doc/index-other.html
- 세팅 방법은 따로 다루진 않을 것이라서 아래 링크를 참고해서 본인의 환경에 맞게 설정하시면 됩니다.
- 예시 데이터베이스 (
world.sql
) 스키마 구조
SELECT
명령어는 SQL에서 데이터를 조회하는 가장 기본적인 명령어입니다. SELECT
구문을 통해 테이블에서 특정 데이터를 선택하고, 필요한 열이나 행을 조건에 맞게 필터링하여 조회할 수 있습니다.
SELECT column1, column2, ...
FROM table_name;
FROM
절은 데이터를 가져올 테이블을 지정합니다. 데이터베이스 내 여러 테이블에서 원하는 테이블을 선택하여 데이터를 조회할 수 있습니다.
예시: country
테이블에서 모든 열을 조회
SELECT * FROM country;
WHERE
절은 특정 조건을 만족하는 행만 조회할 때 사용합니다. WHERE
절을 사용하면 필요한 데이터만 필터링하여 조회할 수 있습니다.
예시: country
테이블에서 인구
가 1억 이상
인 국가 조회
SELECT Name, Population
FROM country
WHERE Population >= 100000000;
IS NOT NULL
조건은 특정 열에 NULL
이 아닌 값이 있는 행만 조회할 때 사용합니다. NULL
값은 데이터가 존재하지 않음을 의미하기 때문에, 이를 제외하고 조회할 수 있습니다. (반대로 IS NULL
조건으로 NULL
값을 가지는 행만 조회할 수 있습니다)
예시: country
테이블에서 IndepYear
값이 NULL이 아닌 국가 조회
SELECT Name, IndepYear
FROM country
WHERE IndepYear IS NOT NULL;
예시: country
테이블에서 IndepYear
값이 NULL인 국가 조회
SELECT Name, IndepYear
FROM country
WHERE IndepYear IS NULL;
DISTINCT
키워드는 조회된 결과에서 중복 값을 제거하고 고유한 값을 반환합니다. 동일한 데이터가 중복으로 포함된 열에서 고유한 값만 필요할 때 유용합니다.
예시: country
테이블에서 고유한 대륙(Continent
) 목록 조회
SELECT DISTINCT Continent
FROM country;
LIMIT
절은 조회 결과에서 반환할 행의 수를 제한할 때 사용됩니다. 많은 데이터를 조회할 때, 제한된 수만큼 데이터를 확인하고 싶을 때 유용합니다.
LIMIT
절은 두 개의 인자를 사용할 수 있으며, 이를 통해 조회 결과의 시작 위치와 행 수를 지정할 수 있습니다.LIMIT row_count
: 조회 결과의 상위 row_count
개의 행만 반환합니다.LIMIT offset, row_count
: offset
부터 시작하여 row_count
개의 행을 반환합니다.LIMIT 0, 10
으로 0번째 행부터 10개의 결과를, 두 번째 페이지는 LIMIT 10, 10
으로 10번째 행부터 10개의 결과를 조회할 수 있습니다.예시: country
테이블에서 인구
가 많은 상위 5개
국가 조회
SELECT Name, Population
FROM country
ORDER BY Population DESC
LIMIT 5;
ORDER BY
는 아래 쪽에서 다시 다룹니다.예시: country
테이블에서 인구
가 많은 국가를 조회하되, 10번째 결과부터 5개의 행
을 반환
SELECT Name, Population
FROM country
ORDER BY Population DESC
LIMIT 10, 5;
아래 예시는 country
테이블에서 인구가 5천만 이상
이고, 대륙이 아시아
인 국가의 이름과 인구를 조회
하는 쿼리입니다. 결과는 중복을 제거
하고 최대 10개
의 행만 반환합니다.
SELECT DISTINCT Name, Population
FROM country
WHERE Population >= 50000000 AND Continent = 'asia'
LIMIT 10;
SELECT DISTINCT
: Name과 Population을 조회하고 중복된 국가 이름은 제외FROM
: country 테이블에서 조회WHERE
: 인구가 5천만 이상이고, 대륙이 아시아인 조건LIMIT
: 최대 10개의 행만 반환INSERT
명령어는 테이블에 새로운 레코드(행)을 추가할 때 사용됩니다. 데이터베이스에 새로운 데이터를 저장하여 정보를 지속적으로 유지하고 관리할 수 있습니다.
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);
예를 들어, city
테이블에 새로운 도시 정보를 추가하려면 다음과 같이 작성할 수 있습니다.
INSERT INTO city (Name, CountryCode, District, Population)
VALUES ('MyNewCity', # Name
'USA', # CountryCode
'MyDistrict', # District
2000000); # Population
# 결과 확인용
SELECT *
FROM city
WHERE CountryCode = 'USA'
AND Population >= 2000000;
한 번에 여러 행을 추가할 수도 있습니다. 행 별로 괄호를 나열하여 작성합니다.
INSERT INTO city (Name, CountryCode, District, Population)
VALUES
('CityA', 'USA', 'DistrictA', 2200000),
('CityB', 'USA', 'DistrictB', 2400000),
('CityC', 'USA', 'DistrictC', 2600000);
# 결과 확인용
SELECT *
FROM city
WHERE CountryCode = 'USA'
AND Population >= 2000000;
UPDATE
명령어는 기존의 레코드를 수정할 때 사용됩니다. 특정 조건을 만족하는 레코드의 값을 업데이트하며, 데이터를 최신 상태로 유지하거나 수정할 때 유용합니다.
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
예를 들어, city
테이블에서 도시 이름이 'CityA'
인 도시의 인구를 3,000,000
으로 업데이트하려면 다음과 같이 작성합니다.
UPDATE city
SET Population = 3000000
WHERE Name = 'CityA';
# 결과 확인용
SELECT *
FROM city
WHERE CountryCode = 'USA'
AND Population >= 2000000;
주의:
WHERE
절을 생략하면 테이블의 모든 행이 업데이트됩니다. 이는 실수로 모든 데이터를 변경할 위험이 있으므로, 꼭 필요한 경우가 아니면 항상WHERE
절을 포함하는 것이 좋습니다.
다수의 열을 동시에 업데이트할 수 있습니다.
UPDATE city
SET Population = 4000000, District = 'DistrictCCC'
WHERE Name = 'CityC';
# 결과 확인용
SELECT *
FROM city
WHERE CountryCode = 'USA'
AND Population >= 2000000;
DELETE
명령어는 특정 조건을 만족하는 레코드를 삭제할 때 사용됩니다. 데이터베이스에서 불필요한 데이터나 더 이상 유효하지 않은 데이터를 제거하는 데 유용합니다.
DELETE FROM table_name
WHERE condition;
예를 들어, city
테이블에서 도시 이름이 'MyNewCity'
인 도시를 삭제하려면 다음과 같이 작성합니다.
DELETE FROM city
WHERE Name = 'MyNewCity';
# 결과 확인용
SELECT *
FROM city
WHERE CountryCode = 'USA'
AND Population >= 2000000;
주의:
WHERE
절을 생략하면 테이블의 모든 행이 삭제됩니다. 이로 인해 데이터 손실이 발생할 수 있으므로, 항상 필요한 경우에만 WHERE 절 없이 DELETE를 사용해야 합니다.
WHERE
절 없이 DELETE FROM table_name;
을 사용할 경우 테이블의 모든 데이터를 삭제하지만, 테이블의 구조는 남아 있습니다. 또한, 삭제된 데이터에 대한 로그가 기록되므로 복구가 가능한 경우가 많습니다.TRUNCATE table_name;
명령어를 사용하면 테이블의 모든 데이터를 삭제하고, 데이터 삭제에 대한 로그가 기록되지 않아 속도가 빠르지만 복구가 불가능합니다. 테이블의 구조는 유지됩니다.DELETE FROM city; -- 테이블의 모든 데이터 삭제 (로그 기록, 느림)
TRUNCATE TABLE city; -- 테이블의 모든 데이터 삭제 (로그 없음, 빠름)
JOIN
과 UNION
은 SQL에서 여러 테이블의 데이터를 결합하여 조회할 때 사용됩니다.
JOIN
은 서로 연관된 테이블의 데이터를 결합하는 반면, UNION
은 두 개의 쿼리 결과를 합쳐주는 역할을 합니다.JOIN
은 두 개 이상의 테이블을 결합하여 하나의 결과를 생성하는 방법으로, 테이블 간 관계를 정의하고 데이터를 조회할 때 유용합니다. JOIN
에는 여러 종류가 있으며, 각 종류에 따라 결합 방식이 다릅니다.
왼쪽 테이블의 모든 행
과 오른쪽 테이블에서 조건에 맞는 행
을 결합하며, 일치하지 않는 오른쪽 테이블의 값은 NULL로 표시됩니다.오른쪽 테이블의 모든 행
과 왼쪽 테이블에서 조건에 맞는 행
을 결합하며, 일치하지 않는 왼쪽 테이블의 값은 NULL로 표시됩니다.INNER JOIN
은 두 테이블에서 조건에 일치하는 행만 결합합니다.
예시: country
테이블과 city
테이블을 국가 코드(CountryCode)를 기준으로 결합하여 각 국가의 수도를 조회합니다.
SELECT co.Name AS Country, ci.Name AS Capital
FROM country AS co
INNER JOIN city AS ci
ON co.Capital = ci.ID;
위 쿼리는 country
와 city
테이블을 Capital
과 ID
열을 기준으로 결합하여 각 국가의 수도 이름을 조회합니다.
LEFT JOIN
은 왼쪽 테이블의 모든 행을 반환하며, 오른쪽 테이블에서 조건에 맞는 행이 있을 경우 해당 데이터를 결합하고, 일치하지 않으면 NULL로 표시됩니다.
RIGHT JOIN
은 테이블 순서만 바꾸면 동일하게 동작합니다예시: country
테이블과 countrylanguage
테이블을 국가 코드(Code)를 기준으로 결합하여 각 국가에서 사용되는 언어를 조회합니다. 국가 코드가 일치하지 않는 경우도 포함합니다.
SELECT co.Name AS Country, cl.Language, cl.IsOfficial
FROM country AS co
LEFT JOIN countrylanguage AS cl
ON co.Code = cl.CountryCode;
이 쿼리는 country
테이블의 모든 국가와 그 국가에서 사용되는 언어를 조회합니다. 언어 정보가 없는 나라는 NULL
로 표시됩니다.
FULL OUTER JOIN
은 두 테이블의 모든 행을 반환하며, 어느 한쪽에만 존재하는 경우에도 포함되며, 일치하지 않는 값은 NULL로 표시됩니다.
MySQL
과 MariaDB
는 FULL OUTER JOIN
을 직접 지원하지 않기 때문에 LEFT JOIN
과 RIGHT JOIN
을 UNION
으로 조합하여 사용할 수 있습니다.UNION
파트에서 함께 다루겠습니다.UNION
은 두 개 이상의 SELECT 쿼리 결과를 합치는 방법으로, 각 쿼리의 열 개수가 같아야 하며, 각 열의 데이터 타입도 서로 호환되어야 합니다.
SELECT column1, column2, ...
FROM table1
UNION
SELECT column1, column2, ...
FROM table2;
UNION
: 중복되는 행을 제거하고 고유한 결과만 반환합니다.UNION ALL
: 중복되는 행도 모두 포함하여 반환합니다.예시 1 : country
와 countrylanguage
테이블의 모든 국가와 언어를 결합하여 조회 (FULL OUTER JOIN)
SELECT co.Name AS Country, cl.Language
FROM country AS co
LEFT JOIN countrylanguage AS cl
ON co.Code = cl.CountryCode
UNION
SELECT co.Name AS Country, cl.Language
FROM countrylanguage AS cl
LEFT JOIN country AS co
ON co.Code = cl.CountryCode;
예시 2 : city
테이블에서 미국(USA)의 도시와 캐나다(CAN)의 도시를 조회하여 합칩니다.
SELECT Name, CountryCode, Population
FROM city
WHERE CountryCode = 'USA'
UNION
SELECT Name, CountryCode, Population
FROM city
WHERE CountryCode = 'CAN';
UNION ALL
을 사용하여 중복도 포함하려면 다음과 같이 작성할 수 있습니다.
SELECT Name, CountryCode, Population
FROM city
WHERE CountryCode = 'USA'
UNION ALL
SELECT Name, CountryCode, Population
FROM city
WHERE CountryCode = 'CAN';
GROUP BY
와 ORDER BY
는 SQL에서 데이터를 그룹화하거나 정렬할 때 사용되는 중요한 명령어입니다.
GROUP BY
는 데이터를 특정 열을 기준으로 그룹화하여 집계 함수와 함께 사용하여 요약된 정보를 얻는 데 유용합니다.ORDER BY
는 데이터를 지정된 열을 기준으로 오름차순 또는 내림차순으로 정렬할 때 사용됩니다.GROUP BY
는 테이블의 데이터를 특정 열을 기준으로 그룹화하고, 각 그룹에 대해 집계 함수(예: COUNT, SUM, AVG, MAX, MIN
)를 적용하여 요약된 정보를 조회할 수 있게 합니다.
SELECT column1, aggregate_function(column2)
FROM table_name
GROUP BY column1;
예시 1. 대륙별 국가 수: country
테이블을 사용하여 대륙(Continent
)별 국가 수를 구해 보겠습니다.
SELECT Continent, COUNT(*) AS CountryCount
FROM country
GROUP BY Continent;
예시 2. 지역별 도시 평균 인구: city
테이블에서 미국(USA)의 지역(District
)별 평균 인구를 조회합니다.
SELECT District, AVG(Population) AS AvgPopulation
FROM city
WHERE CountryCode = 'USA'
GROUP BY District;
HAVING
절은 GROUP BY
와 함께 사용하여 그룹화된 결과에 조건을 적용할 때 사용됩니다.
WHERE
절은 그룹화 전에 개별 행을 필터링하는 데 사용되고, HAVING
절은 그룹화 후 결과에 조건을 적용합니다.예시 1+. 대륙별 국가 수 + HAVING: country
테이블을 사용하여 대륙(Continent
)별 국가 수를 구한 테이블에서 국가 수가 30개 이상
인 대륙만을 반환해보겠습니다.
SELECT Continent, COUNT(*) AS CountryCount
FROM country
GROUP BY Continent
HAVING COUNT(*) >= 30;
ORDER BY
는 조회된 데이터를 특정 열을 기준으로 오름차순 또는 내림차순으로 정렬하는 데 사용됩니다.
ASC
)으로 정렬되며, DESC
를 지정합니다.SELECT column1, column2
FROM table_name
ORDER BY column1 [ASC|DESC];
예시 1. 인구가 많은 국가 조회: country
테이블에서 인구가 많은 순서대로 국가를 조회합니다.
SELECT Name, Population
FROM country
ORDER BY Population DESC; # 내림차순
예시 2. 지역별 도시 이름을 알파벳 순서로 조회: city
테이블에서 특정 지역(District
)의 도시 이름을 알파벳 순서로 정렬합니다.
SELECT Name, District
FROM city
WHERE District = 'California'
ORDER BY Name ASC; # 오름차순 (ASC 생략가능)
GROUP BY
와 ORDER BY
는 함께 사용할 수 있으며, 각 그룹의 결과를 정렬하여 원하는 결과를 얻을 수 있습니다.
예시: country
테이블에서 대륙별 국가 수를 구한 후, 국가 수가 많은 대륙 순으로 정렬합니다.
SELECT Continent, COUNT(*) AS CountryCount
FROM country
GROUP BY Continent
ORDER BY CountryCount DESC;
이와 같이 GROUP BY
와 ORDER BY
를 사용하여 데이터를 그룹화하고 정렬함으로써, 더 나은 분석과 데이터 요약이 가능합니다.
GROUP BY
는 집계 함수와 함께 사용하여 데이터를 요약하고, ORDER BY
는 결과를 보기 쉽게 정렬하는 데 중요한 역할을 합니다.SQL 쿼리를 작성할 때는 일반적으로 SELECT
문법에 따른 작성 순서로 작성하지만, 데이터베이스 엔진은 실제 쿼리를 처리할 때 내부적으로 실행 순서에 따라 처리합니다.
SQL 작성 순서는 쿼리의 논리적인 순서로, 일반적으로 다음과 같은 순서를 따릅니다.
SELECT
: 반환할 열을 지정DISTINCT
: 중복 제거FROM
: 데이터를 가져올 테이블 지정JOIN
: 다른 테이블과의 결합ON
: JOIN의 조건 지정WHERE
: 행을 필터링할 조건 지정GROUP BY
: 특정 열을 기준으로 그룹화HAVING
: 그룹화된 결과에 조건 적용ORDER BY
: 결과 정렬LIMIT
: 결과의 개수 제한OFFSET
: 시작 위치 지정SELECT DISTINCT c.Name AS CountryName,
MAX(c.Population) AS MaxPopulation
FROM country AS c
JOIN city ON c.Code = city.CountryCode
WHERE c.Population > 1000000
GROUP BY c.Name
HAVING COUNT(c.Name) > 1
ORDER BY MaxPopulation DESC
LIMIT 10
OFFSET 5;
SQL의 실행 순서는 데이터베이스 엔진
이 쿼리를 처리하는 실제 순서로, 효율적인 데이터 검색을 위해 작성 순서와 다르게 처리됩니다.
FROM
: 데이터를 가져올 테이블 결정ON
: JOIN 조건을 확인하여 테이블을 결합JOIN
: 테이블 간의 결합 수행WHERE
: 필터링 조건 적용하여 행 선택GROUP BY
: 특정 열을 기준으로 데이터 그룹화HAVING
: 그룹화된 데이터에 조건 적용SELECT
: 반환할 열을 선택DISTINCT
: 중복 행 제거ORDER BY
: 지정된 열을 기준으로 정렬LIMIT
: 결과 행 수 제한OFFSET
: 시작 위치 지정위의 작성 예시 쿼리를 기준으로 보면, 데이터베이스 엔진
은 FROM
절에서 시작하여 OFFSET
절까지의 순서로 쿼리를 처리합니다.
JOIN
은 FROM
과 ON
절 이후에 처리되며, WHERE
필터링이 적용된 후에 GROUP BY
가 처리됩니다. SELECT
, DISTINCT
, ORDER BY
, LIMIT
은 마지막에 수행됩니다.이번 포스팅에서는 SQL의 기본 개념과 DML(Data Manipulation Language)을 통한 CRUD 작업을 비롯해, JOIN
과 UNION
을 사용한 다중 테이블 결합, GROUP BY
및 ORDER BY
를 통한 데이터 그룹화와 정렬까지 다루었습니다.
또한, SQL 작성 및 실행 순서에 대한 이해를 통해 SQL 쿼리의 처리 흐름
을 파악하고 성능을 최적화하는 방법도 살펴보았습니다.
이처럼 SQL은 데이터를 효율적으로 관리하고 분석하는 데 필수적인 도구입니다.
다음 포스팅에서는 SQL 내장 함수, 조건문, 그리고 서브쿼리를 다루어, 보다 심화된 데이터 처리와 분석 방법을 알아보겠습니다.