AD JB Toolbox 01

MariaDB 강좌 / VIEW로 자주 쓰는 조회를 정의하기

VIEW는 자주 사용하는 SELECT 정의를 데이터베이스 객체로 저장해 이름으로 조회하는 기능입니다. 일반 뷰는 조회 결과 행 자체를 별도로 보관하는 테이블이 아니며, 권한 기준과 수정 가능 여부는 뷰 정의에 따라 확인해야 합니다.

한 문장용 CTE와 저장된 조회 정의 구분하기

여러 보고서에서 결제 주문별 상품 금액을 반복 계산한다면 같은 SELECT 정의를 뷰로 관리할 수 있습니다. CTE는 한 SQL 문 안의 이름이고 VIEW는 생성 후 다른 문장에서도 사용할 수 있는 객체입니다. 어느 열을 공개할지와 기존 프로그램이 기대하는 열 이름을 함께 설계합니다. 한 문장 안에서만 필요한 이름은 WITH로 공통 테이블 식 만들고 쿼리 나누기과 비교하고, 저장된 뷰를 누가 실행할 수 있는지는 사용자 계정 만들고 필요한 권한만 부여하기의 계정·권한 범위로 검토합니다.

대상 보관하는 것 수명
일반 VIEW SELECT 정의 DROP VIEW까지
CTE 한 문장의 중간 조회 이름 그 SQL 문 안
실제 테이블 저장된 행 삭제·정책에 따라 유지

원본 테이블과 별도의 뷰 이름 준비하기

학습용 MariaDB 서버의 shopcourse에 course_user로 접속합니다. 명령줄 클라이언트와 UTF-8 SQL 파일 실행 방법대로 코드를 UTF-8 파일에 저장하고 SOURCE C:/mariadb-lab/lesson.sql;처럼 실제 파일 경로로 실행할 수 있습니다. SQL 문은 운영체제 터미널이 아닌 MariaDB 연결 안에서 실행합니다.

먼저 SELECT VERSION(), DATABASE();와 SHOW TABLES;로 대상 서버·DB·이름 중복을 확인합니다. 아래 c34_customers, c34_products, c34_orders, c34_items는 이 글의 독립된 연습용 이름입니다. 이미 존재하면 정의와 행을 확인하고, 보관할 자료가 없는 이 글의 실습 테이블임이 확실할 때만 마지막 절의 정리 순서로 지운 뒤 다시 만듭니다. 기존 강좌의 동명 없는 테이블이나 운영 데이터는 삭제하지 않습니다.

USE shopcourse;
CREATE TABLE c34_customers (
 customer_id INT NOT NULL PRIMARY KEY,
 customer_name VARCHAR(50) NOT NULL,
 city VARCHAR(30) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE c34_products (
 product_id INT NOT NULL PRIMARY KEY,
 product_name VARCHAR(100) NOT NULL,
 category VARCHAR(30) NOT NULL,
 price DECIMAL(10,2) NOT NULL CHECK (price >= 0),
 stock INT NOT NULL CHECK (stock >= 0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE c34_orders (
 order_id INT NOT NULL PRIMARY KEY,
 customer_id INT NOT NULL,
 ordered_at DATETIME NOT NULL,
 status VARCHAR(20) NOT NULL,
 shipping_fee DECIMAL(10,2) NOT NULL DEFAULT 1000,
 CONSTRAINT fk_c34_order_customer FOREIGN KEY (customer_id)
  REFERENCES c34_customers(customer_id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE c34_items (
 order_id INT NOT NULL,
 product_id INT NOT NULL,
 quantity INT NOT NULL CHECK (quantity > 0),
 unit_price DECIMAL(10,2) NOT NULL CHECK (unit_price >= 0),
 PRIMARY KEY (order_id, product_id),
 CONSTRAINT fk_c34_item_order FOREIGN KEY (order_id)
  REFERENCES c34_orders(order_id) ON DELETE RESTRICT,
 CONSTRAINT fk_c34_item_product FOREIGN KEY (product_id)
  REFERENCES c34_products(product_id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO c34_customers VALUES
 (1,'김민수','서울'),(2,'이서연','부산'),
 (3,'박지우','서울'),(4,'최하늘','대전');
INSERT INTO c34_products VALUES
 (1,'노트','문구',3500,20),(2,'볼펜','문구',1500,50),
 (3,'머그컵','생활',8000,12),(4,'스탠드','생활',25000,5);
INSERT INTO c34_orders
 (order_id,customer_id,ordered_at,status,shipping_fee) VALUES
 (101,1,'2026-01-10 10:00:00','paid',1000),
 (102,1,'2026-01-20 11:00:00','paid',1000),
 (103,2,'2026-02-05 12:00:00','paid',1000),
 (104,3,'2026-02-10 13:00:00','canceled',1000);
INSERT INTO c34_items VALUES
 (101,1,2,3500),(101,2,3,1500),(102,3,1,8000),
 (103,1,1,3500),(103,3,2,8000),(104,2,1,1500);

c34_paid_order_totals라는 이름의 기존 뷰도 없는지 SHOW FULL TABLES로 확인합니다. 이 실습은 처음 생성하는 객체이므로 CREATE OR REPLACE로 기존 정의를 자동 덮어쓰지 않습니다. 실제 변경 전에는 SHOW CREATE VIEW로 현재 정의를 백업해야 합니다.

INVOKER 기준으로 조회 정의 저장하고 사용하기

CREATE SQL SECURITY INVOKER VIEW c34_paid_order_totals AS
SELECT o.order_id,o.customer_id,o.ordered_at,
 SUM(i.quantity*i.unit_price) AS goods_total
FROM c34_orders o JOIN c34_items i ON i.order_id=o.order_id
WHERE o.status='paid' GROUP BY o.order_id,o.customer_id,o.ordered_at;
SELECT order_id,goods_total FROM c34_paid_order_totals ORDER BY order_id;
SHOW CREATE VIEW c34_paid_order_totals;

조회 결과는 101번 11500.00, 102번 8000.00, 103번 19500.00입니다. 뷰의 정렬에 의존하지 않고 사용 시 ORDER BY를 명시합니다. INVOKER는 뷰를 호출하는 계정의 권한으로 원본 접근을 검사하도록 명시한 설정이며 호출 계정에 필요한 원본 권한도 있어야 합니다. CREATE VIEW와 SQL SECURITY를 확인하세요.

원본 변경이 조회 결과에 반영되는지 확인하기

START TRANSACTION;
UPDATE c34_items SET quantity=3 WHERE order_id=101 AND product_id=1;
SELECT goods_total FROM c34_paid_order_totals WHERE order_id=101;
ROLLBACK;
SELECT goods_total FROM c34_paid_order_totals WHERE order_id=101;

같은 연결의 트랜잭션 안에서 101번 주문 노트 수량을 2에서 3으로 바꾸면 뷰의 금액은 15000.00이 됩니다. 취소 뒤에는 다시 11500.00입니다. 뷰에 복사된 과거 행을 갱신한 것이 아니라 원본에 대한 조회 결과가 바뀐 것입니다. 다른 연결에서 보이는 시점은 격리 수준과 확정 여부에 영향을 받습니다.

권한·수정 가능성·성능의 경계 확인하기

이 뷰는 GROUP BY와 SUM을 사용하므로 뷰를 통해 임의로 원본 행을 수정할 수 있는 형태로 취급하지 않습니다. 단순 뷰 중 수정 가능한 경우가 있어도 모든 뷰가 UPDATE 가능한 것은 아닙니다. 원본을 수정하는 경로와 집계 보고 경로를 나누는 편이 안전합니다.

DEFINER 방식은 정의자 계정의 권한과 계정 수명에 영향을 받습니다. 정의자가 사라진 복원 환경에서 오류가 날 수 있으므로 덤프·복원 시 해당 속성을 확인해야 합니다. 뷰를 만들었다고 실행 결과가 자동 캐시되거나 항상 빨라지지는 않으며 실행 계획으로 평가합니다.

정의 변경과 정리 순서 확인하기

열 이름을 바꾸거나 제거하면 사용하는 쿼리에 영향을 줄 수 있습니다. SELECT *보다 공개 열을 명시하고 의존 관계를 확인한 뒤 정의를 변경합니다. 뷰가 없는 테이블을 참조하도록 남지 않게 정리 시 뷰부터 지웁니다. DROP VIEW는 이 예제의 원본 테이블 행을 삭제하지 않습니다.

DROP VIEW shopcourse.c34_paid_order_totals;

반복하기 전 현재 DB와 실제 정의·행을 확인하고 필요한 자료를 백업합니다. 보관할 데이터가 없는 이 글의 전용 실습 객체만 아래 순서로 정리합니다. 외래키가 있으면 자식부터 지웁니다. DROP TABLE은 구조와 데이터를 모두 없애며 일반적인 ROLLBACK으로 복원되지 않으므로 취소 가능한 DML 실습과 분리합니다.

DROP TABLE shopcourse.c34_items;
DROP TABLE shopcourse.c34_orders;
DROP TABLE shopcourse.c34_products;
DROP TABLE shopcourse.c34_customers;
같은 카테고리의 다른 글
MariaDB / Query / LEFT JOIN, RIGHT JOIN, INNER JOIN

MariaDB / Query / LEFT JOIN, RIGHT JOIN, INNER JOIN

SQL의 JOIN은 여러 테이블을 한 번에 나타낼 때 사용합니다. 대표적인 JOIN 방식은 LEFT JOIN, RIGHT JOIN, INNER JOIN이 있습니다. 다음은 세 가지 JOIN의 차이를 알아보기 위한 간단한 예제 테이블입니다.

MariaDB 강좌 / 복제 구조와 지연·오류·장애 대응 이해하기

MariaDB 강좌 / 복제 구조와 지연·오류·장애 대응 이해하기

빈 두 서버를 준비하는 로컬 Compose 구성과 복제 상태·지연·오류 진단을 설명합니다. 적용 중지·재개를 관찰하고 백업과 장애 승격의 경계를 구분합니다.

MariaDB / 사용자 관리하는 방법

MariaDB / 사용자 관리하는 방법

MariaDB에서 사용자를 만드는 방법, 수정하는 방법, 삭제하는 방법, 권한을 부여하고 제거하는 방법을 알아봅니다.

MariaDB 강좌 / 중복 데이터를 줄이는 정규화와 주문 데이터베이스 설계

MariaDB 강좌 / 중복 데이터를 줄이는 정규화와 주문 데이터베이스 설계

주문 상세에 반복한 고객 정보의 변경 오류를 관찰하고 키별 사실을 네 테이블로 나눕니다. 부분·이행 종속, 거래 당시 단가와 스냅샷 보존, 무결성 제약과 성능의 별도 검토를 설명합니다.

MariaDB 강좌 / 서브쿼리·EXISTS·NOT EXISTS로 조건 표현하기

MariaDB 강좌 / 서브쿼리·EXISTS·NOT EXISTS로 조건 표현하기

평균값 서브쿼리와 EXISTS·NOT EXISTS를 상품·고객·주문으로 실습합니다. 한 값의 반환 조건, 상관 키 누락, paid 주문 부재의 정의와 NOT IN의 NULL 함정을 설명합니다.

MariaDB 강좌 / Docker로 MariaDB 실습 환경 만들기

MariaDB 강좌 / Docker로 MariaDB 실습 환경 만들기

Compose 파일로 MariaDB 포트·암호 파일·데이터 볼륨·헬스체크를 구성합니다. 연결 확인과 컨테이너 교체 실습을 통해 데이터 유지, 초기화와 접속 오류의 차이를 이해합니다.

MariaDB / 데이터베이스 / 조회, 생성, 삭제, 이름 변경

MariaDB / 데이터베이스 / 조회, 생성, 삭제, 이름 변경

MariaDB에서 데이터베이스를 조회하는 방법, 생성하는 방법, 삭제하는 방법, 이름을 변경하는 방법에 대해서 알아봅니다.

MariaDB 강좌 / COUNT·SUM·AVG·MIN·MAX로 집계하기

MariaDB 강좌 / COUNT·SUM·AVG·MIN·MAX로 집계하기

COUNT·SUM·AVG·MIN·MAX의 집계 대상과 단위를 상품 재고로 비교합니다. NULL·0·빈 결과의 차이, 행별 계산 후 합계, 최솟값과 해당 행을 혼동하지 않는 기준을 설명합니다.

MariaDB 강좌 / Ubuntu에 MariaDB 설치하고 서버 실행하기

MariaDB 강좌 / Ubuntu에 MariaDB 설치하고 서버 실행하기

Ubuntu APT 설치 후 서버 실행·자동 시작·관리자 소켓 인증을 확인합니다. 로컬 TCP 학습 계정을 만들고 패키지 버전, 인증 오류와 서비스 로그를 확인하는 절차를 설명합니다.

MariaDB 강좌 / 서버 설정·SQL 모드·시간대·로그 확인하기

MariaDB 강좌 / 서버 설정·SQL 모드·시간대·로그 확인하기

설정 파일·GLOBAL·SESSION의 차이를 기준으로 MariaDB 동작을 확인합니다. SQL 모드 오류와 TIMESTAMP·DATETIME 시간대 실습, 로그 조건 점검 및 변경 복구 절차를 제공합니다.