Retrieve all rows from the left table, with matched rows from the right table:
// Get all users and their posts (if they have any)const result = await db.select() .from(users) .leftJoin(posts, eq(users.id, posts.userId));// Users without posts will have posts: null// [// { users: {...}, posts: {...} },// { users: {...}, posts: null }, // User with no posts// ]
Left joins return all rows from the left table. If no match is found in the right table, the right side fields will be null.
Retrieve all rows from the right table, with matched rows from the left table:
// Get all posts with their authors (even if author is missing)const result = await db.select() .from(users) .rightJoin(posts, eq(users.id, posts.userId));// Posts without users will have users: null// [// { users: {...}, posts: {...} },// { users: null, posts: {...} }, // Post with deleted user// ]
// Get all users and all posts, matched where possibleconst result = await db.select() .from(users) .fullJoin(posts, eq(users.id, posts.userId));// Both sides can be null// [// { users: {...}, posts: {...} }, // Matched// { users: {...}, posts: null }, // User without posts// { users: null, posts: {...} }, // Post without user// ]
Full join is PostgreSQL-specific. It’s not available in MySQL or SQLite.
// Every user paired with every postconst result = await db.select() .from(users) .crossJoin(posts);// No join condition needed// If 5 users and 10 posts, returns 50 rows
import { eq, gt } from 'drizzle-orm';// Only users older than 18 with their postsconst result = await db.select() .from(users) .leftJoin(posts, eq(users.id, posts.userId)) .where(gt(users.age, 18));
import { alias } from 'drizzle-orm/pg-core';// Create an alias for self-joinconst managers = alias(users, 'managers');// Get employees with their managersconst result = await db.select({ employeeName: users.name, managerName: managers.name,}) .from(users) .leftJoin(managers, eq(users.managerId, managers.id));
import { sql } from 'drizzle-orm';// Get each user with their 3 most recent postsconst latestPosts = db.select() .from(posts) .where(eq(posts.userId, users.id)) .orderBy(desc(posts.createdAt)) .limit(3) .as('latest_posts');const result = await db.select() .from(users) .leftJoinLateral(latestPosts, sql`true`);
import { students, courses, enrollments } from './schema';// Get students with their enrolled coursesconst result = await db.select({ studentName: students.name, courseName: courses.name,}) .from(students) .innerJoin(enrollments, eq(students.id, enrollments.studentId)) .innerJoin(courses, eq(enrollments.courseId, courses.id));