Documentation
Select

SQL Select

Drizzle ORM provide you the most SQL-like way to query your relational database.
We natively support mostly every query feature capability of every dialect and whatever we do not yet support - can be done with our powerful sql operator

Basic and partial select

Getting a list of all users and you will have a typed result set

const result: User[] = await db.select().from(users);
 
result[0].id;
result[0].name;
select * from 'users';

Whenever you have SQL table with many columns you might not wanna select all of them for either performance or security reasons.
You can omit them by using our partial query syntax which will generate partial SQL select and automatically map results

const result = await db.select({
    field1: users.id,
    field2: users.name,
  }).from(users);
 
const { field1, field2 } = result[0];
select "users"."id" as "field1", "users"."name" as "field2" from "users";

With partial select you can apply sql transformations with sql operator

const result = await db.select({
    id: users.id,
    lowerName: sql`lower(${users.name})`,
  }).from(users);
select "users"."id", lower("users"."name") as "lowerName" from "users";

You can also select fields conditionally

async function selectUsers(withName: boolean) {
  return db
    .select({
      id: users.id,
      ...(withName ? { name: users.name } : {}),
    })
    .from(users);
}
 
const users = await selectUsers(true);

Select filters

You can filter SQL results with our list of filter operators

import { eq, lt, gte, ne } from "drizzle-orm";
 
await db.select().from(users).where(eq(users.id, 42));
await db.select().from(users).where(lt(users.id, 42));
await db.select().from(users).where(gte(users.id, 42));
await db.select().from(users).where(ne(users.id, 42));
...
select * from 'users' where 'id' = 42;
select * from 'users' where 'id' < 42;
select * from 'users' where 'id' >= 42;
select * from 'users' where 'id' <> 42;

Any filter operator is a sql operator under the hood, for full SQL potential you can utilise it directly and build type safe and future safe queries
You can safely alter schema, rename tables and columns and it will automatically reflect in queries, as opposed to having regular string raw SQL queries

import { sql } from "drizzle-orm";
 
await db.select().from(users).where(sql`${users.id} < 42`);
await db.select().from(users).where(sql`${users.id} = 42`);
await db.select().from(users).where(sql`${users.id} >= 42`);
await db.select().from(users).where(sql`${users.id} <> 42`);
await db.select().from(users).where(sql`lower(${users.name}) = "aaron"`);
select * from 'users' where 'id' = 42;
select * from 'users' where 'id' < 42;
select * from 'users' where 'id' <> 42;
select * from 'users' where 'id' >= 42;
select * from 'users' where lower('name') = "aaron";

Inverting condition with a not operator

import { eq, not, sql } from "drizzle-orm";
 
await db.select().from(users).where(not(eq(users.id, 42)));
await db.select().from(users).where(sql`not ${users.id} = 42`);
select * from 'users' where not 'id' = 42;
select * from 'users' where not 'id' = 42;

Combining filters

You can logically combine filter operators with conditional and and or operators

import { eq, and, sql } from "drizzle-orm";
 
await db.select().from(users).where(
  and(
    eq(users.id, 42), 
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 and ${users.name} = "Dan"`);
select * from 'users' where 'id' = 42 and 'name' = "Dan";
select * from 'users' where 'id' = 42 and 'name' = "Dan";
import { eq, or, sql } from "drizzle-orm";
 
await db.select().from(users).where(
  or(
    eq(users.id, 42), 
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 or ${users.name} = "Dan"`);
select * from 'users' where 'id' = 42 or 'name' = "Dan";
select * from 'users' where 'id' = 42 or 'name' = "Dan";

Distinct

You can use the distinct keyword to retrieve unique or distinct values from a column or set of columns in a query result. It eliminates duplicate rows, returning only the unique values.

await db.selectDistinct().from(users).orderBy(usersTable.id, usersTable.name);
 
await db.selectDistinct({ id: users.id }).from(users).orderBy(usersTable.id);
select distinct "id", "name" from "users" order by "users"."id", "users"."name";
 
select distinct "id" from "users" order by "users"."id";

Drizzle ORM supports DISTINCT ON PostgreSQL operator too

đź’ˇ

DISTINCT ON is only available in PostgreSQL

await db.selectDistinctOn([users.id])
        .from(users)
        .orderBy(users.id);
 
await db.selectDistinctOn([users.name], { name: users.name })
        .from(users)
        .orderBy(users.name);
select distinct on ("users"."id") "id", "name" from "users" order by "users"."id";
 
select distinct on ("users"."name") "name" from "users" order by "users"."name";

Limit & Offset

You can apply limit and offset to the query

await db.select().from(users).limit(10);
await db.select().from(users).limit(10).offset(10);
select * from "users" limit 10;
select * from "users" limit 10 offset 10;

Order By

You can sort results with orderBy operator

import { asc, desc } from "drizzle-orm";
 
await db.select().from(users).orderBy(users.name);
await db.select().from(users).orderBy(desc(users.name));
 
// you can pass multiple order args
await db.select().from(users).orderBy(users.name, users.name2);
await db.select().from(users).orderBy(asc(users.name), desc(users.name2));
select * from "users" order by "name";
select * from "users" order by "name" desc;
 
select * from "users" order by "name" "name2";
select * from "users" order by "name" asc "name2" desc;

WITH clause

SQL with clause - is a statement scoped view, helpful to organise complex queries

const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));
 
const result = await db.with(sq).select().from(sq);
with sq as (select * from "users" where "users"."id" = 42)
select * from sq;

To select raw sql in a WITH subquery and reference that field in other queries, you must add an alias to it

 
const sq = db.$with('sq').as(db.select({ 
    name: sql<string>`upper(${users.name})`.as('name') 
  })
  .from(users));
 
const result = await db.with(sq).select({ name: sq.name }).from(sq);

If you don't provide an alias - field type will become DrizzleTypeError and you won't be able to reference it in other queries. If you ignore the type error and still try to reference the field, you will get a runtime error, since there's no way to reference that field without an alias.

Select from subquery

Just like in SQL - you can embed SQL queries into other SQL queries by using subquery API

const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(sq);
select * from (select * from "user" where "user"."id" = 42) "sq";

You can also use subqueries in joins

const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));

Aggregations

With Drizzle ORM you can do aggregations with functions like sum, count, avg, etc. by grouping and filtering with groupBy and having respectfully, just like you do in SQL.

With our powerful sql operator you can infer aggregations functions return types using sql<number> syntax

import { pgTable, serial, text, doublePrecision } from 'drizzle-orm/pg-core';
import { gte } from 'drizzle-orm';
 
export const product = pgTable('product', {
  id: serial('id').primaryKey(),
  name: text('name'),
  unitPrice: doublePrecision("unit_price")
});
 
const result = await db.select({ count: sql<number>`count(*)` }).from(product);
result[0].count // will be number type
 
await db.select({ count: sql<number>`count(*)` }).from(product).where(gte(product.unitPrice, 4));
 
select count(*) from "product";
select count(*) from "product" where "unit_price" >= 4;

Lets have a quick look on how to group and filter grouped using a having

import { pgTable, serial, text } from 'drizzle-orm/pg-core';
 
export const user = pgTable('user', {
  id: serial('id').primaryKey(),
  name: text('name'),
  city: text("city"),
});
 
await db.select({ count: sql<number>`count(${user.id})`, city: user.city })
  .from(user)
  .groupBy(({ city }) => city)
 
await db.select({ count: sql<number>`count(${user.id})`, city: user.city })
  .from(user)
  .groupBy(({ city }) => city)
  .having(({ count }) => count)
select count("id"), "city" from "user" group by "user"."city";
select count("id"), "city" from "user" group by "user"."city" having count("user"."id");

Here's a more advanced example

const orders = sqliteTable('order', {
  id: integer('id').primaryKey(),
  orderDate: integer('order_date', { mode: 'timestamp' }).notNull(),
  requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(),
  shippedDate: integer('shipped_date', { mode: 'timestamp' }),
  shipVia: integer('ship_via').notNull(),
  freight: numeric('freight').notNull(),
  shipName: text('ship_name').notNull(),
  shipCity: text('ship_city').notNull(),
  shipRegion: text('ship_region'),
  shipPostalCode: text('ship_postal_code'),
  shipCountry: text('ship_country').notNull(),
  customerId: text('customer_id').notNull(),
  employeeId: integer('employee_id').notNull(),
});
 
const details = sqliteTable('order_detail', {
  unitPrice: numeric('unit_price').notNull(),
  quantity: integer('quantity').notNull(),
  discount: numeric('discount').notNull(),
  orderId: integer('order_id').notNull(),
  productId: integer('product_id').notNull(),
});
 
 
db
  .select({
    id: orders.id,
    shippedDate: orders.shippedDate,
    shipName: orders.shipName,
    shipCity: orders.shipCity,
    shipCountry: orders.shipCountry,
    productsCount: sql<number>`count(${details.productId})`,
    quantitySum: sql<number>`sum(${details.quantity})`,
    totalPrice: sql<number>`sum(${details.quantity} * ${details.unitPrice})`,
  })
  .from(orders)
  .leftJoin(details, eq(orders.id, details.orderId))
  .groupBy(orders.id)
  .orderBy(asc(orders.id))
  .all();