集合操作

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

并集 (Union)

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

获取来自 customers 和 users 表的所有名称,排除重复项。

PostgreSQL
MySQL
SQLite
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
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
import { integer, pgTable, text, varchar } from "drizzle-orm/pg-core";

const users = pgTable('sellers', {
    id: integer('id').primaryKey(),
    name: varchar('name', { length: 256 }).notNull(),
    address: text('address'),
});

const customers = pgTable('customers', {
    id: integer('id').primaryKey(),
    name: varchar('name', { length: 256 }).notNull(),
    city: text('city'),
    email: varchar('email', { length: 256 }).notNull()
});
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 ?
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 ?
import { int, mysqlTable, text, varchar } from "drizzle-orm/mysql-core";

const users = mysqlTable('sellers', {
    id: int('id').primaryKey(),
    name: varchar('name', { length: 256 }).notNull(),
    address: text('address'),
});

const customers = mysqlTable('customers', {
    id: int('id').primaryKey(),
    name: varchar('name', { length: 256 }).notNull(),
    city: text('city'),
    email: varchar('email', { length: 256 }).notNull()
});
import-pattern
builder-pattern
schema.ts
import { union } from 'drizzle-orm/sqlite-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 ?
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 ?
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

const users = sqliteTable('sellers', {
    id: int('id').primaryKey(),
    name: text('name').notNull(),
    address: text('address'),
});

const customers = sqliteTable('customers', {
    id: int('id').primaryKey(),
    name: text('name').notNull(),
    city: text('city'),
    email: text('email').notNull()
});

并集全部 (Union All)

将来自两个查询块的所有结果合并为一个结果,包括重复项。

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

PostgreSQL
MySQL
SQLite
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";

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' }),
});

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 { 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 { 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 { int, mysqlTable, text, timestamp, varchar } from "drizzle-orm/mysql-core";

const onlineSales = mysqlTable('online_sales', {
    transactionId: int('transaction_id').primaryKey(),
    productId: int('product_id').unique(),
    quantitySold: int('quantity_sold'),
    saleDate: timestamp('sale_date', { mode: 'date' }),
});

const inStoreSales = mysqlTable('in_store_sales', {
    transactionId: int('transaction_id').primaryKey(),
    productId: int('product_id').unique(),
    quantitySold: int('quantity_sold'),
    saleDate: timestamp('sale_date', { mode: 'date' }),
});
import-pattern
builder-pattern
schema.ts
import { unionAll } from 'drizzle-orm/sqlite-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 { int, sqliteTable } from "drizzle-orm/sqlite-core";

const onlineSales = sqliteTable('online_sales', {
    transactionId: int('transaction_id').primaryKey(),
    productId: int('product_id').unique(),
    quantitySold: int('quantity_sold'),
    saleDate: int('sale_date', { mode: 'timestamp' }),
});

const inStoreSales = sqliteTable('in_store_sales', {
    transactionId: int('transaction_id').primaryKey(),
    productId: int('product_id').unique(),
    quantitySold: int('quantity_sold'),
    saleDate: int('sale_date', { mode: 'timestamp' }),
});

交集 (Intersect)

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

假设您有两个存储有关学生课程选修信息的表。您想找到两个不同部门之间共有的课程, 但您希望得到不同的课程名称,并且不考虑相同学生多次选修同一门课程。

在这种情况下,您希望找到两个部门之间共有的课程,但不想多次计数相同课程,即使同一部门的多个学生都选修了它。

PostgreSQL
MySQL
SQLite
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";

const depA = pgTable('department_a_courses', {
    studentId: integer('student_id'),
    courseName: varchar('course_name').notNull(),
});

const depB = pgTable('department_b_courses', {
    studentId: integer('student_id'),
    courseName: varchar('course_name').notNull(),
});
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 `projects_name` from `department_a_projects`
intersect
select `projects_name` from `department_b_projects`
import { depA, depB } from './schema'

const result = await db
  .select({ courseName: depA.courseName })
  .from(depA)
  .intersect(db.select({ courseName: depB.courseName }).from(depB));
select `projects_name` from `department_a_projects`
intersect
select `projects_name` from `department_b_projects`
import { int, mysqlTable, varchar } from "drizzle-orm/mysql-core";

const depA = mysqlTable('department_a_courses', {
    studentId: int('student_id'),
    courseName: varchar('course_name', { length: 256 }).notNull(),
});

const depB = pgTable('department_b_courses', {
    studentId: int('student_id'),
    courseName: varchar('course_name', { length: 256 }).notNull(),
});
import-pattern
builder-pattern
schema.ts
import { intersect } from 'drizzle-orm/sqlite-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 { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

const depA = sqliteTable('department_a_courses', {
    studentId: int('student_id'),
    courseName: text('course_name').notNull(),
});

const depB = sqliteTable('department_b_courses', {
    studentId: int('student_id'),
    courseName: text('course_name').notNull(),
});

交集全部 (Intersect All)

仅合并两个查询块结果中共有的行,包括重复项。

假设您有两个包含客户订单数据的表,并且您想要确定普通客户和 VIP 客户都订购的产品。在这种情况下,您希望跟踪每个产品的数量,即使不同客户多次订购同一产品。

在这种情况下,您希望找到普通客户和 VIP 客户都订购的产品,但您希望保留数量信息,即使相同产品被不同客户多次订购。

PostgreSQL
MySQL
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";

const regularCustomerOrders = pgTable('regular_customer_orders', {
    customerId: integer('customer_id').primaryKey(),
    productId: integer('product_id').notNull(),
    quantityOrdered: integer('quantity_ordered').notNull(),
});

const vipCustomerOrders = pgTable('vip_customer_orders', {
    customerId: integer('customer_id').primaryKey(),
    productId: integer('product_id').notNull(),
    quantityOrdered: integer('quantity_ordered').notNull(),
});
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`
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 { int, mysqlTable } from "drizzle-orm/mysql-core";

const regularCustomerOrders = mysqlTable('regular_customer_orders', {
    customerId: int('customer_id').primaryKey(),
    productId: int('product_id').notNull(),
    quantityOrdered: int('quantity_ordered').notNull(),
});

const vipCustomerOrders = mysqlTable('vip_customer_orders', {
    customerId: int('customer_id').primaryKey(),
    productId: int('product_id').notNull(),
    quantityOrdered: int('quantity_ordered').notNull(),
});

差集 (Except)

对于两个查询块 A 和 B,返回 A 中独有的结果,即不包含在 B 中的结果,省略重复项。

假设您有两个存储员工项目分配信息的表。您想找到仅属于一个部门且与另一个部门不共享的项目,排除重复项。

在这种情况下,您想要确定仅属于一个部门且与另一个部门不共享的项目。您不想多次计数相同的项目, 即使同一部门的多个员工被分配到它。

PostgreSQL
MySQL
SQLite
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";

const depA = pgTable('department_a_projects', {
    employeeId: integer('employee_id'),
    projectsName: varchar('projects_name').notNull(),
});

const depB = pgTable('department_b_projects', {
    employeeId: integer('employee_id'),
    projectsName: varchar('projects_name').notNull(),
});
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`
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 { int, mysqlTable, varchar } from "drizzle-orm/mysql-core";

const depA = mysqlTable('department_a_projects', {
    employeeId: int('employee_id'),
    projectsName: varchar('projects_name', { length: 256 }).notNull(),
});

const depB = mysqlTable('department_b_projects', {
    employeeId: int('employee_id'),
    projectsName: varchar('projects_name', { length: 256 }).notNull(),
});
import-pattern
builder-pattern
schema.ts
import { except } from 'drizzle-orm/sqlite-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 { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

const depA = sqliteTable('department_a_projects', {
    employeeId: int('employee_id'),
    projectsName: text('projects_name').notNull(),
});

const depB = sqliteTable('department_b_projects', {
    employeeId: int('employee_id'),
    projectsName: text('projects_name').notNull(),
});

差集全部 (Except All)

对于两个查询块 A 和 B,返回 A 中独有的结果,即不包含在 B 中的结果,包括重复项。

假设您有两个包含客户订单数据的表,并且您想要确定仅由普通客户(没有 VIP 客户)订购的产品。在这种情况下,您希望跟踪每个产品的数量,即使不同普通客户多次订购同一产品。

在这种情况下,您想要找到仅由普通客户订购(没有 VIP 客户订购)的产品。您希望保留数量信息,即使不同普通客户多次订购同一产品。

PostgreSQL
MySQL
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";

const regularCustomerOrders = pgTable('regular_customer_orders', {
    customerId: integer('customer_id').primaryKey(),
    productId: integer('product_id').notNull(),
    quantityOrdered: integer('quantity_ordered').notNull(),
});

const vipCustomerOrders = pgTable('vip_customer_orders', {
    customerId: integer('customer_id').primaryKey(),
    productId: integer('product_id').notNull(),
    quantityOrdered: integer('quantity_ordered').notNull(),
});
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`
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`
const regularCustomerOrders = mysqlTable('regular_customer_orders', {
    customerId: int('customer_id').primaryKey(),
    productId: int('product_id').notNull(),
    quantityOrdered: int('quantity_ordered').notNull(),
});

const vipCustomerOrders = mysqlTable('vip_customer_orders', {
    customerId: int('customer_id').primaryKey(),
    productId: int('product_id').notNull(),
    quantityOrdered: int('quantity_ordered').notNull(),
});
Become a Gold Sponsor