집합 연산

SQL 집합 연산은 여러 쿼리 블록의 결과를 하나로 합칩니다. SQL 표준은 다음과 같은 세 가지 집합 연산을 정의합니다: UNION, INTERSECT, EXCEPT, UNION ALL, INTERSECT ALL, EXCEPT ALL.

Union

두 쿼리 블록의 모든 결과를 하나로 합치고, 중복된 값을 제거합니다.

customersusers 테이블에서 중복 없이 모든 이름을 가져옵니다.

PostgreSQL
MySQL
SQLite
SingleStore
import-pattern
builder-pattern
schema.ts
import { union } from 'drizzle-orm/pg-core'
import { users, customers } from './schema'

const allNamesForUserQuery = db.select({ name: users.name }).from(users);

const result = await union(
    allNamesForUserQuery,
    db.select({ name: customers.name }).from(customers)
).limit(10);
(select "name" from "sellers")
union
(select "name" from "customers")
limit $1

UNION ALL

두 쿼리 블록의 결과를 중복을 포함하여 하나의 결과로 합칩니다.

온라인 판매와 매장 판매를 나타내는 두 개의 테이블이 있다고 가정해 봅시다. 이 경우, 두 테이블의 데이터를 하나의 결과 집합으로 합치고 싶을 수 있습니다. 중복된 거래가 있을 수 있으므로 모든 레코드를 유지하고 중복을 제거하지 않습니다.

PostgreSQL
MySQL
SQLite
SingleStore
import-pattern
builder-pattern
schema.ts
import { unionAll } from 'drizzle-orm/pg-core'
import { onlineSales, inStoreSales } from './schema'

const onlineTransactions = db.select({ transaction: onlineSales.transactionId }).from(onlineSales);
const inStoreTransactions = db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales);

const result = await unionAll(onlineTransactions, inStoreTransactions);
select "transaction_id" from "online_sales"
union all
select "transaction_id" from "in_store_sales"

교집합(Intersect)

두 쿼리 블록의 결과 중 공통된 행만 결합하고, 중복은 제거합니다.

학생들의 수강 정보를 저장하는 두 테이블이 있다고 가정해 봅시다. 두 개의 다른 학과에서 공통으로 제공하는 강좌를 찾고 싶지만, 동일한 학생이 동일한 강좌를 여러 번 수강한 경우는 제외하고 싶습니다.

이 시나리오에서는 두 학과에서 공통으로 제공하는 강좌를 찾되, 동일한 강좌가 여러 학생에 의해 수강된 경우에도 중복으로 계산하지 않기를 원합니다.

PostgreSQL
MySQL
SQLite
SingleStore
import-pattern
builder-pattern
schema.ts
import { intersect } from 'drizzle-orm/pg-core'
import { depA, depB } from './schema'

const departmentACourses = db.select({ courseName: depA.courseName }).from(depA);
const departmentBCourses = db.select({ courseName: depB.courseName }).from(depB);

const result = await intersect(departmentACourses, departmentBCourses);
select "course_name" from "department_a_courses"
intersect
select "course_name" from "department_b_courses"

Intersect All

두 쿼리 블록의 결과에서 공통된 행만 결합하고, 중복된 값을 유지합니다.

예를 들어, 일반 고객과 VIP 고객의 주문 데이터가 담긴 두 테이블이 있다고 가정해봅시다. 이때, 일반 고객과 VIP 고객 모두가 주문한 제품을 식별하고자 합니다. 이 경우, 여러 고객이 동일한 제품을 여러 번 주문하더라도 각 제품의 수량 정보를 유지해야 합니다.

이 시나리오에서는 일반 고객과 VIP 고객 모두가 주문한 제품을 찾되, 여러 고객이 동일한 제품을 여러 번 주문한 경우에도 수량 정보를 유지해야 합니다.

PostgreSQL
MySQL
SingleStore
import-pattern
builder-pattern
schema.ts
import { intersectAll } from 'drizzle-orm/pg-core'
import { regularCustomerOrders, vipCustomerOrders } from './schema'

const regularOrders = db.select({ 
    productId: regularCustomerOrders.productId,
    quantityOrdered: regularCustomerOrders.quantityOrdered }
).from(regularCustomerOrders);

const vipOrders = db.select({ 
    productId: vipCustomerOrders.productId,
    quantityOrdered: vipCustomerOrders.quantityOrdered }
).from(vipCustomerOrders);

const result = await intersectAll(regularOrders, vipOrders);
select "product_id", "quantity_ordered" from "regular_customer_orders"
intersect all
select "product_id", "quantity_ordered" from "vip_customer_orders"

Except

두 개의 쿼리 블록 A와 B가 있을 때, A의 결과 중 B에도 존재하지 않는 결과만 반환하며, 중복은 제거합니다.

예를 들어, 직원들의 프로젝트 할당 정보를 저장하는 두 개의 테이블이 있다고 가정해 봅시다. 여러분은 한 부서에만 속하고 다른 부서와 공유되지 않는 프로젝트를 찾고 싶습니다. 이때 동일한 프로젝트가 여러 직원에게 할당되어 있어도 중복 없이 한 번만 카운트하고 싶습니다.

이 시나리오에서는 한 부서에만 속하고 다른 부서와 공유되지 않는 프로젝트를 식별하려고 합니다. 동일한 프로젝트가 여러 번 카운트되지 않도록 중복을 제거합니다.

PostgreSQL
MySQL
SQLite
SingleStore
import-pattern
builder-pattern
schema.ts
import { except } from 'drizzle-orm/pg-core'
import { depA, depB } from './schema'

const departmentACourses = db.select({ courseName: depA.projectsName }).from(depA);
const departmentBCourses = db.select({ courseName: depB.projectsName }).from(depB);

const result = await except(departmentACourses, departmentBCourses);
select "projects_name" from "department_a_projects"
except
select "projects_name" from "department_b_projects"

Except All

두 쿼리 블록 A와 B가 있을 때, A의 결과 중 B에도 존재하지 않는 모든 결과를 반환합니다. 이때 중복된 결과도 포함됩니다.

예를 들어, 고객 주문 데이터를 담고 있는 두 테이블이 있고, 일반 고객만 주문한 제품을 찾고 싶은 경우를 생각해봅시다. VIP 고객이 주문하지 않은 제품을 찾고자 합니다. 이때, 동일한 제품이 여러 일반 고객에 의해 여러 번 주문된 경우에도 수량 정보를 유지하려고 합니다.

이 시나리오에서는 일반 고객만 주문한 제품을 찾고, VIP 고객이 주문하지 않은 제품을 식별합니다. 동일한 제품이 여러 일반 고객에 의해 여러 번 주문된 경우에도 수량 정보를 유지합니다.

PostgreSQL
MySQL
SingleStore
import-pattern
builder-pattern
schema.ts
import { exceptAll } from 'drizzle-orm/pg-core'
import { regularCustomerOrders, vipCustomerOrders } from './schema'

const regularOrders = db.select({ 
    productId: regularCustomerOrders.productId,
    quantityOrdered: regularCustomerOrders.quantityOrdered }
).from(regularCustomerOrders);

const vipOrders = db.select({ 
    productId: vipCustomerOrders.productId,
    quantityOrdered: vipCustomerOrders.quantityOrdered }
).from(vipCustomerOrders);

const result = await exceptAll(regularOrders, vipOrders);
select "product_id", "quantity_ordered" from "regular_customer_orders"
except all
select "product_id", "quantity_ordered" from "vip_customer_orders"