集合操作

SQL 集合操作将多个查询块的结果合并为单个结果。
SQL 标准定义了以下三种集合操作:UNIONINTERSECTEXCEPTUNION ALLINTERSECT ALLEXCEPT ALL

Union

将两个查询块中的所有结果合并为一个结果,并省略任何重复项。

从 customers 和 users 表中获取所有不重复的名称。

import-pattern
builder-pattern
schema.ts
import { union } from 'drizzle-orm/mysql-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 10

Union All

将两个查询块中的所有结果合并为一个结果,并保留重复项。

假设你有两个表,一个代表在线销售,另一个代表门店销售。在这种情况下,你希望将这两个表中的数据合并为一个结果集。由于可能存在重复的交易,你希望保留所有记录,而不删除重复项。

import-pattern
builder-pattern
schema.ts
import { unionAll } from 'drizzle-orm/mysql-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`)

交集

仅合并两个查询块结果中共有的那些行,并省略任何重复项。

假设你有两个存储学生课程选修信息的表。
你想找出两个不同院系之间共有的课程,
但你希望得到不同的课程名称,并且你不关心统计同一学生对同一课程的多次选修。

在这种情况下,你想找出两个院系之间共有的课程,但又不想
即使同一院系的多个学生都选修了同一课程,也将该课程计算多次。

import-pattern
builder-pattern
schema.ts
import { intersect } from 'drizzle-orm/mysql-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`)

交集全部

仅合并两个查询块结果中共有的那些行,并保留重复项。

让我们考虑这样一个场景:你有两个包含客户订单数据的表,想要识别既被普通客户又被 VIP 客户订购的产品。在这种情况下,你希望跟踪每个产品的数量,即使它被不同客户多次订购。

在这个场景中,你想找出既被普通客户又被 VIP 客户订购的产品,但即使同一个产品被不同客户多次订购,你也希望保留数量信息。

import-pattern
builder-pattern
schema.ts
import { intersectAll } from 'drizzle-orm/mysql-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 中的结果,并省略任何重复项。

假设你有两个表,用来存储员工项目分配的信息。
你想找出只属于一个部门、而不与另一个部门共享的项目,并排除重复项。

在这种情况下,你想识别那些只属于一个部门、且不与另一个部门共享的项目。你不希望对同一个项目
计算多次,即使同一部门中的多个员工被分配到了它。

import-pattern
builder-pattern
schema.ts
import { except } from 'drizzle-orm/mysql-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 客户下单的产品。你希望保留数量信息,即使同一种产品被不同的普通客户多次下单。

import-pattern
builder-pattern
schema.ts
import { exceptAll } from 'drizzle-orm/mysql-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`)