集合运算
SQL 集合运算将多个查询块的结果合并为一个单一结果。
SQL 标准定义了以下三种集合运算:UNION、INTERSECT、EXCEPT、UNION ALL、INTERSECT ALL、EXCEPT ALL。
并集
将两个查询块的所有结果合并为一个结果,并省略任何重复项。
从 customers 和 users 表中获取所有不重复的名称。
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 -- 参数: [10] import { users , customers } from './schema'
const result = await db
.select ({ name : users .name })
.from (users)
.union ( db .select ({ name : customers .name }) .from (customers))
.limit ( 10 ); ( select "name" from "sellers" )
union
( select "name" from "customers" )
limit $ 1 -- 参数: [10] import { integer , pgTable , text , varchar } from "drizzle-orm/pg-core" ;
export const users = pgTable ( 'sellers' , {
id : integer () .primaryKey () ,
name : varchar ({ length : 256 }) .notNull () ,
address : text () ,
});
export const customers = pgTable ( 'customers' , {
id : integer () .primaryKey () ,
name : varchar ({ length : 256 }) .notNull () ,
city : text () ,
email : varchar ({ length : 256 }) .notNull ()
});
Union All
将两个查询块中的所有结果合并为一个结果,保留重复项。
让我们考虑一个场景:你有两张表,一张表示在线销售,另一张表示门店销售。在这种情况下,你希望将这两张表中的数据合并为一个结果集。由于可能存在重复交易,你希望保留所有记录,而不消除重复项。
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" ) import { onlineSales , inStoreSales } from './schema'
const result = await db
.select ({ transaction : onlineSales .transactionId })
.from (onlineSales)
.unionAll (
db .select ({ transaction : inStoreSales .transactionId }) .from (inStoreSales)
); ( select "transaction_id" from "online_sales" )
union all
( select "transaction_id" from "in_store_sales" ) import { integer , pgTable , text , timestamp , varchar } from "drizzle-orm/pg-core" ;
export const onlineSales = pgTable ( 'online_sales' , {
transactionId : integer ( 'transaction_id' ) .primaryKey () ,
productId : integer ( 'product_id' ) .unique () ,
quantitySold : integer ( 'quantity_sold' ) ,
saleDate : timestamp ( 'sale_date' , { mode : 'date' }) ,
});
export const inStoreSales = pgTable ( 'in_store_sales' , {
transactionId : integer ( 'transaction_id' ) .primaryKey () ,
productId : integer ( 'product_id' ) .unique () ,
quantitySold : integer ( 'quantity_sold' ) ,
saleDate : timestamp ( 'sale_date' , { mode : 'date' }) ,
});
交集
仅合并两个查询块结果中共有的行,并省略任何重复项。
假设你有两个表,存储学生课程选课信息。
你想找出两个不同院系之间共有的课程,
但你只想要不同的课程名称,并且你不关心统计同一学生对同一课程的多次
选课记录。
在这个场景中,你想找出两个院系之间共有的课程,但不希望
即使同一院系的多个学生选了同一门课,也把同一课程重复计数。
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" ) import { depA , depB } from './schema'
const result = await db
.select ({ courseName : depA .courseName })
.from (depA)
.intersect ( db .select ({ courseName : depB .courseName }) .from (depB)); ( select "course_name" from "department_a_courses" )
intersect
( select "course_name" from "department_b_courses" ) import { integer , pgTable , varchar } from "drizzle-orm/pg-core" ;
export const depA = pgTable ( 'department_a_courses' , {
studentId : integer ( 'student_id' ) ,
courseName : varchar ( 'course_name' ) .notNull () ,
});
export const depB = pgTable ( 'department_b_courses' , {
studentId : integer ( 'student_id' ) ,
courseName : varchar ( 'course_name' ) .notNull () ,
});
交集全部
仅合并两个查询块结果中共有的那些行,并保留重复项。
假设有两个包含客户订单数据的表,你想要识别既被普通客户又被 VIP 客户订购的产品。在这种情况下,你希望跟踪每个产品的数量,即使它被不同客户多次订购。
在这个场景中,你想找到既被普通客户又被 VIP 客户订购的产品,但你希望保留数量信息,即使同一个产品被不同客户多次订购。
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" ) import { regularCustomerOrders , vipCustomerOrders } from './schema'
const result = await db
.select ({
productId : regularCustomerOrders .productId ,
quantityOrdered : regularCustomerOrders .quantityOrdered ,
})
.from (regularCustomerOrders)
.intersectAll (
db
.select ({
productId : vipCustomerOrders .productId ,
quantityOrdered : vipCustomerOrders .quantityOrdered ,
})
.from (vipCustomerOrders)
); ( select "product_id" , "quantity_ordered" from "regular_customer_orders" )
intersect all
( select "product_id" , "quantity_ordered" from "vip_customer_orders" ) import { integer , pgTable } from "drizzle-orm/pg-core" ;
export const regularCustomerOrders = pgTable ( 'regular_customer_orders' , {
customerId : integer ( 'customer_id' ) .primaryKey () ,
productId : integer ( 'product_id' ) .notNull () ,
quantityOrdered : integer ( 'quantity_ordered' ) .notNull () ,
});
export const vipCustomerOrders = pgTable ( 'vip_customer_orders' , {
customerId : integer ( 'customer_id' ) .primaryKey () ,
productId : integer ( 'product_id' ) .notNull () ,
quantityOrdered : integer ( 'quantity_ordered' ) .notNull () ,
});
Except
对于两个查询块 A 和 B,返回 A 中所有不同时也出现在 B 中的结果,并省略任何重复项。
假设你有两张表,用于存储员工的项目分配信息。
你想找出某个部门独有的项目,
而不是与另一个部门共享的项目,并排除重复项。
在这个场景中,你想识别只属于一个部门且
不与另一个部门共享的项目。即使同一部门的多个员工被分配到同一个项目,你也不想将同一个项目
计算多次。
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" ) import { depA , depB } from './schema'
const result = await db
.select ({ courseName : depA .projectsName })
.from (depA)
.except ( db .select ({ courseName : depB .projectsName }) .from (depB)); ( select "projects_name" from "department_a_projects" )
except
( select "projects_name" from "department_b_projects" ) import { integer , pgTable , varchar } from "drizzle-orm/pg-core" ;
export const depA = pgTable ( 'department_a_projects' , {
employeeId : integer ( 'employee_id' ) ,
projectsName : varchar ( 'projects_name' ) .notNull () ,
});
export const depB = pgTable ( 'department_b_projects' , {
employeeId : integer ( 'employee_id' ) ,
projectsName : varchar ( 'projects_name' ) .notNull () ,
});
Except All
对于两个查询块 A 和 B,返回 A 中所有不同时也出现在 B 中的结果,保留重复项。
让我们考虑这样一个场景:你有两张包含客户订单数据的表,并且你想要识别那些只被普通客户下单(不被 VIP 客户下单)的产品。
在这种情况下,你希望跟踪每种产品的数量,即使它被不同的普通客户多次下单。
在这个场景中,你希望找出那些只被普通客户下单、而没有被 VIP 客户下单的产品。你希望保留数量信息,即使同一种产品被不同的普通客户多次下单也是如此。
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" ) import { regularCustomerOrders , vipCustomerOrders } from './schema'
const result = await db
.select ({
productId : regularCustomerOrders .productId ,
quantityOrdered : regularCustomerOrders .quantityOrdered ,
})
.from (regularCustomerOrders)
.exceptAll (
db
.select ({
productId : vipCustomerOrders .productId ,
quantityOrdered : vipCustomerOrders .quantityOrdered ,
})
.from (vipCustomerOrders)
); ( select "product_id" , "quantity_ordered" from "regular_customer_orders" )
except all
( select "product_id" , "quantity_ordered" from "vip_customer_orders" ) import { integer , pgTable } from "drizzle-orm/pg-core" ;
export const regularCustomerOrders = pgTable ( 'regular_customer_orders' , {
customerId : integer ( 'customer_id' ) .primaryKey () ,
productId : integer ( 'product_id' ) .notNull () ,
quantityOrdered : integer ( 'quantity_ordered' ) .notNull () ,
});
export const vipCustomerOrders = pgTable ( 'vip_customer_orders' , {
customerId : integer ( 'customer_id' ) .primaryKey () ,
productId : integer ( 'product_id' ) .notNull () ,
quantityOrdered : integer ( 'quantity_ordered' ) .notNull () ,
});