Class SelectQueryBuilder<DB, TB, O>

Expression represents an arbitrary SQL expression with a type.

Most Kysely methods accept instances of Expression and most classes like SelectQueryBuilder and the return value of the sql template tag implement it.

const exp1: Expression<string> = sql<string>`CONCAT('hello', ' ', 'world')`
const exp2: Expression<{ first_name: string }> = db.selectFrom('person').select('first_name')

You can implement the Expression interface to create your own type-safe utilities for Kysely.

Type Parameters

  • DB

  • TB extends keyof DB

  • O

Hierarchy

  • SelectQueryBuilder

Implements

Constructors

Methods

  • Asserts that query's output row type equals the given type T.

    This method can be used to simplify excessively complex types to make typescript happy and much faster.

    Kysely uses complex type magic to achieve its type safety. This complexity is sometimes too much for typescript and you get errors like this:

    error TS2589: Type instantiation is excessively deep and possibly infinite.
    

    In these case you can often use this method to help typescript a little bit. When you use this method to assert the output type of a query, Kysely can drop the complex output type that consists of multiple nested helper types and replace it with the simple asserted type.

    Using this method doesn't reduce type safety at all. You have to pass in a type that is structurally equal to the current type.

    Examples

    const result = await db
    .with('first_and_last', (qb) => qb
    .selectFrom('person')
    .select(['first_name', 'last_name'])
    .$assertType<{ first_name: string, last_name: string }>()
    )
    .with('age', (qb) => qb
    .selectFrom('person')
    .select('age')
    .$assertType<{ age: number }>()
    )
    .selectFrom(['first_and_last', 'age'])
    .selectAll()
    .executeTakeFirstOrThrow()

    Type Parameters

    • T

    Returns O extends T ? SelectQueryBuilder<DB, TB, T> : KyselyTypeError<"$assertType() call failed: The type passed in is not equal to the output type of the query.">

  • Call func(this) if condition is true.

    NOTE: This method has an impact on typescript performance and it should only be used when necessary. Remember that you can call most methods like where conditionally like this:

    let query = db.selectFrom('person').selectAll()

    if (firstName) {
    query = query.where('first_name', '=', firstName)
    }

    const result = await query.execute()

    This method is mainly useful with optional selects. Any select or selectAll method called inside the callback add optional fields to the result type. This is because we can't know if those selections were actually made before running the code.

    Also see this recipe

    Examples

    async function getPerson(id: number, withLastName: boolean) {
    return await db
    .selectFrom('person')
    .select(['id', 'first_name'])
    .$if(withLastName, (qb) => qb.select('last_name'))
    .where('id', '=', id)
    .executeTakeFirstOrThrow()
    }

    Any selections added inside the if callback will be added as optional fields to the output type since we can't know if the selections were actually made before running the code. In the example above the return type of the getPerson function is:

    {
    id: number
    first_name: string
    last_name?: string
    }

    You can also call any other methods inside the callback:

    const { count } = db.fn

    db.selectFrom('person')
    .select('person.id')
    .$if(filterByFirstName, (qb) => qb.where('first_name', '=', firstName))
    .$if(filterByPetCount, (qb) => qb
    .innerJoin('pet', 'pet.owner_id', 'person.id')
    .having(count('pet.id'), '>', petCountLimit)
    .groupBy('person.id')
    )

    Type Parameters

    • O2

    Parameters

    Returns SelectQueryBuilder<DB, TB, MergePartial<O, O2>>

  • Deprecated

    Use $assertType instead.

    Type Parameters

    • T

    Returns O extends T ? SelectQueryBuilder<DB, TB, T> : KyselyTypeError<"assertType() call failed: The type passed in is not equal to the output type of the query.">

  • Executes the query and returns the first result or undefined if the query returned no result.

    Returns Promise<SimplifySingleResult<O>>

  • Executes the query and returns the first result or throws if the query returned no result.

    By default an instance of NoResultError is thrown, but you can provide a custom error class as the only argument to throw a different error.

    Parameters

    Returns Promise<{ [ K in string | number | symbol]: O[K] }>

  • Executes query with explain statement before select keyword.

    const explained = await db
    .selectFrom('person')
    .where('gender', '=', 'female')
    .selectAll()
    .explain('json')

    The generated SQL (MySQL):

    explain format=json select * from `person` where `gender` = ?
    

    You can also execute explain analyze statements.

    import { sql } from 'kysely'

    const explained = await db
    .selectFrom('person')
    .where('gender', '=', 'female')
    .selectAll()
    .explain('json', sql`analyze`)

    The generated SQL (PostgreSQL):

    explain (analyze, format json) select * from "person" where "gender" = $1
    

    Type Parameters

    • ER extends Record<string, any> = Record<string, any>

    Parameters

    Returns Promise<ER[]>

  • Adds a group by clause to the query.

    Examples

    importsql } from 'kysely'

    await db
    .selectFrom('person')
    .select([
    'first_name',
    sql`max(id)`.as('max_id')
    ])
    .groupBy('first_name')
    .execute()

    The generated SQL (PostgreSQL):

    select "first_name", max(id)
    from "person"
    group by "first_name"

    groupBy also accepts an array:

    importsql } from 'kysely'

    await db
    .selectFrom('person')
    .select([
    'first_name',
    'last_name',
    sql`max(id)`.as('max_id')
    ])
    .groupBy([
    'first_name',
    'last_name'
    ])
    .execute()

    The generated SQL (PostgreSQL):

    select "first_name", "last_name", max(id)
    from "person"
    group by "first_name", "last_name"

    The group by expressions can also be subqueries or raw sql expressions:

    import { sql } from 'kysely'

    await db
    .selectFrom('person')
    .select([
    'first_name',
    'last_name',
    sql`max(id)`.as('max_id')
    ])
    .groupBy([
    sql`concat(first_name, last_name)`,
    (qb) => qb.selectFrom('pet').select('id').limit(1)
    ])
    .execute()

    dynamic.ref can be used to refer to columns not known at compile time:

    async function someQuery(groupBy: string) {
    const { ref } = db.dynamic

    return await db
    .selectFrom('person')
    .select('first_name')
    .groupBy(ref(groupBy))
    .execute()
    }

    someQuery('first_name')

    The generated SQL (PostgreSQL):

    select "first_name"
    from "person"
    group by "first_name"

    Parameters

    • groupBy: readonly GroupByExpression<DB, TB, O>[]

    Returns SelectQueryBuilder<DB, TB, O>

  • Parameters

    • groupBy: GroupByExpression<DB, TB, O>

    Returns SelectQueryBuilder<DB, TB, O>

  • Joins another table to the query using an inner join.

    Examples

    Simple usage by providing a table name and two columns to join:

    const result = await db
    .selectFrom('person')
    .innerJoin('pet', 'pet.owner_id', 'person.id')
    // `select` needs to come after the call to `innerJoin` so
    // that you can select from the joined table.
    .select('person.id', 'pet.name')
    .execute()

    result[0].id
    result[0].name

    The generated SQL (PostgreSQL):

    select "person"."id", "pet"."name"
    from "person"
    inner join "pet"
    on "pet"."owner_id" = "person"."id"

    You can give an alias for the joined table like this:

    await db.selectFrom('person')
    .innerJoin('pet as p', 'p.owner_id', 'person.id')
    .where('p.name', '=', 'Doggo')
    .selectAll()
    .execute()

    The generated SQL (PostgreSQL):

    select *
    from "person"
    inner join "pet" as "p"
    on "p"."owner_id" = "person"."id"
    where "p".name" = $1

    You can provide a function as the second argument to get a join builder for creating more complex joins. The join builder has a bunch of on* methods for building the on clause of the join. There's basically an equivalent for every where method (on, onRef, onExists etc.). You can do all the same things with the on method that you can with the corresponding where method. See the where method documentation for more examples.

    await db.selectFrom('person')
    .innerJoin(
    'pet',
    (join) => join
    .onRef('pet.owner_id', '=', 'person.id')
    .on('pet.name', '=', 'Doggo')
    )
    .selectAll()
    .execute()

    The generated SQL (PostgreSQL):

    select *
    from "person"
    inner join "pet"
    on "pet"."owner_id" = "person"."id"
    and "pet"."name" = $1

    You can join a subquery by providing a select query (or a callback) as the first argument:

    await db.selectFrom('person')
    .innerJoin(
    db.selectFrom('pet')
    .select(['owner_id', 'name'])
    .where('name', '=', 'Doggo')
    .as('doggos'),
    'doggos.owner_id',
    'person.id',
    )
    .selectAll()
    .execute()

    The generated SQL (PostgreSQL):

    select *
    from "person"
    inner join (
    select "owner_id", "name"
    from "pet"
    where "name" = $1
    ) as "doggos"
    on "doggos"."owner_id" = "person"."id"

    Type Parameters

    Parameters

    • table: TE
    • k1: K1
    • k2: K2

    Returns SelectQueryBuilderWithInnerJoin<DB, TB, O, TE>

  • Type Parameters

    Parameters

    • table: TE
    • callback: FN

    Returns SelectQueryBuilderWithInnerJoin<DB, TB, O, TE>

  • Adds a limit clause to the query.

    Examples

    Select the first 10 rows of the result:

    return await db
    .selectFrom('person')
    .select('first_name')
    .limit(10)

    Select rows from index 10 to index 19 of the result:

    return await db
    .selectFrom('person')
    .select('first_name')
    .offset(10)
    .limit(10)

    Parameters

    • limit: number

    Returns SelectQueryBuilder<DB, TB, O>

  • Adds an order by clause to the query.

    orderBy calls are additive. To order by multiple columns, call orderBy multiple times.

    The first argument is the expression to order by and the second is the order (asc or desc).

    Examples

    await db
    .selectFrom('person')
    .select('person.first_name as fn')
    .orderBy('id')
    .orderBy('fn', 'desc')
    .execute()

    The generated SQL (PostgreSQL):

    select "person"."first_name" as "fn"
    from "person"
    order by "id" asc, "fn" desc

    The order by expression can also be a raw sql expression or a subquery in addition to column references:

    importsql } from 'kysely'

    await db
    .selectFrom('person')
    .selectAll()
    .orderBy((qb) => qb.selectFrom('pet')
    .select('pet.name')
    .whereRef('pet.owner_id', '=', 'person.id')
    .limit(1)
    )
    .orderBy(
    sql`concat(first_name, last_name)`
    )
    .execute()

    The generated SQL (PostgreSQL):

    select *
    from "person"
    order by
    ( select "pet"."name"
    from "pet"
    where "pet"."owner_id" = "person"."id"
    limit 1
    ) asc,
    concat(first_name, last_name) asc

    dynamic.ref can be used to refer to columns not known at compile time:

    async function someQuery(orderBy: string) {
    const { ref } = db.dynamic

    return await db
    .selectFrom('person')
    .select('person.first_name as fn')
    .orderBy(ref(orderBy))
    .execute()
    }

    someQuery('fn')

    The generated SQL (PostgreSQL):

    select "person"."first_name" as "fn"
    from "person"
    order by "fn" asc

    Parameters

    Returns SelectQueryBuilder<DB, TB, O>

  • Adds a select clause to the query.

    When a column (or any expression) is selected, Kysely adds its type to the return type of the query. Kysely is smart enough to parse the column names and types even from aliased columns, subqueries, raw expressions etc.

    Kysely only allows you to select columns and expressions that exist and would produce valid SQL. However, Kysely is not perfect and there may be cases where the type inference doesn't work and you need to override it. You can always use the dynamic module and the sql tag to override the types.

    Select calls are additive. Calling select('id').select('first_name') is the same as calling select(['id', 'first_name']).

    To select all columns of the query or specific tables see the selectAll method.

    See the $if method if you are looking for a way to add selections based on a runtime condition.

    Examples

    Select a single column:

    const persons = await db.selectFrom('person')
    .select('id')
    .where('first_name', '=', 'Arnold')
    .execute()

    persons[0].id

    The generated SQL (PostgreSQL):

    select "id" from "person" where "first_name" = $1
    

    Select a single column and specify a table:

    const persons = await db.selectFrom(['person', 'pet'])
    .select('person.id')
    .execute()

    persons[0].id

    The generated SQL (PostgreSQL):

    select "person"."id" from "person", "pet"
    

    Select multiple columns:

    const persons = await db.selectFrom('person')
    .select(['person.id', 'first_name'])
    .execute()

    persons[0].id
    persons[0].first_name

    The generated SQL (PostgreSQL):

    select "person"."id", "first_name" from "person"
    

    Aliased selections:

    const persons = await db.selectFrom('person')
    .select([
    'person.first_name as fn',
    'person.last_name as ln'
    ])
    .execute()

    persons[0].fn
    persons[0].ln

    The generated SQL (PostgreSQL):

    select
    "person"."first_name" as "fn",
    "person"."last_name" as "ln"
    from "person"

    You can also select subqueries and raw sql expressions. Note that you always need to give a name for the selections using the as method:

    importsql } from 'kysely'

    const persons = await db.selectFrom('person')
    .select([
    (qb) => qb
    .selectFrom('pet')
    .whereRef('person.id', '=', 'pet.owner_id')
    .select('pet.name')
    .limit(1)
    .as('pet_name')
    sql<string>`concat(first_name, ' ', last_name)`.as('full_name')
    ])
    .execute()

    persons[0].pet_name
    persons[0].full_name

    The generated SQL (PostgreSQL):

    select
    (
    select "pet"."name"
    from "pet"
    where "person"."id" = "pet"."owner_id"
    limit $1
    ) as "pet_name",
    concat(first_name, ' ', last_name) as full_name
    from "person"

    In case you use the sql tag you need to specify the type of the expression (in this example string).

    All the examples above assume you know the column names at compile time. While it's better to build your code like that (that way you also know the types) sometimes it's not possible or you just prefer to write more dynamic code.

    In this example, we use the dynamic module's methods to add selections dynamically:

    const { ref } = db.dynamic

    // Some column name provided by the user. Value not known at compile time.
    const columnFromUserInput = req.query.select;

    // A type that lists all possible values `columnFromUserInput` can have.
    // You can use `keyof Person` if any column of an interface is allowed.
    type PossibleColumns = 'last_name' | 'first_name' | 'birth_date'

    const spersons = await db.selectFrom('person')
    .select([
    ref<PossibleColumns>(columnFromUserInput)
    'id'
    ])
    .execute()

    // The resulting type contains all `PossibleColumns` as optional fields
    // because we cannot know which field was actually selected before
    // running the code.
    const lastName: string | undefined = persons[0].last_name
    const firstName: string | undefined = persons[0].first_name
    const birthDate: string | undefined = persons[0].birth_date

    // The result type also contains the compile time selection `id`.
    persons[0].id

    Type Parameters

    Parameters

    • selections: readonly SE[]

    Returns QueryBuilderWithSelection<DB, TB, O, SE>

  • Type Parameters

    Parameters

    • selection: SE

    Returns QueryBuilderWithSelection<DB, TB, O, SE>

  • Adds a select * or select table.* clause to the query.

    Examples

    const persons = await db
    .selectFrom('person')
    .selectAll()
    .execute()

    The generated SQL (PostgreSQL):

    select * from "person"
    

    Select all columns of a table:

    const persons = await db
    .selectFrom('person')
    .selectAll('person')
    .execute()

    The generated SQL (PostgreSQL):

    select "person".* from "person"
    

    Select all columns of multiple tables:

    const personsPets = await db
    .selectFrom(['person', 'pet'])
    .selectAll(['person', 'pet'])
    .execute()

    The generated SQL (PostgreSQL):

    select "person".*, "pet".* from "person", "pet"
    

    Type Parameters

    • T extends string | number | symbol

    Parameters

    • table: readonly T[]

    Returns SelectAllQueryBuilder<DB, TB, O, T>

  • Type Parameters

    • T extends string | number | symbol

    Parameters

    • table: T

    Returns SelectAllQueryBuilder<DB, TB, O, T>

  • Returns SelectAllQueryBuilder<DB, TB, O, TB>

  • Executes the query and streams the rows.

    The optional argument chunkSize defines how many rows to fetch from the database at a time. It only affects some dialects like PostgreSQL that support it.

    Examples

    const stream = db.
    .selectFrom('person')
    .select(['first_name', 'last_name'])
    .where('gender', '=', 'other')
    .stream()

    for await (const person of stream) {
    console.log(person.first_name)

    if (person.last_name === 'Something') {
    // Breaking or returning before the stream has ended will release
    // the database connection and invalidate the stream.
    break
    }
    }

    Parameters

    • chunkSize: number = 100

    Returns AsyncIterableIterator<O>

  • Creates the OperationNode that describes how to compile this expression into SQL.

    If you are creating a custom expression, it's often easiest to use the sql template tag to build the node:

    class SomeExpression<T> implements Expression<T> {
    toOperationNode(): OperationNode {
    return sql`some sql here`.toOperationNode()
    }
    }

    Returns SelectQueryNode

  • Adds a where clause to the query.

    Also see orWhere, whereExists and whereRef.

    Examples

    Find a row by column value:

    const person = await db
    .selectFrom('person')
    .selectAll()
    .where('id', '=', 100)
    .executeTakeFirst()

    The generated SQL (PostgreSQL):

    select * from "person" where "id" = $1
    

    Operator can be any supported operator or if the typings don't support it you can always use

    sql`your operator`
    

    The next example uses the > operator:

    const persons = await db
    .selectFrom('person')
    .selectAll()
    .where('id', '>', 100)
    .execute()

    The generated SQL (PostgreSQL):

    select * from "person" where "id" > $1
    

    where methods don't change the type of the query. You can add conditional statements easily by doing something like this:

    let query = db
    .selectFrom('person')
    .selectAll()

    if (firstName) {
    // The query builder is immutable. Remember to reassign
    // the result back to the query variable.
    query = query.where('first_name', '=', firstName)
    }

    const persons = await query.execute()

    This is true for basically all methods execpt the select and returning, that do change the return type of the query.

    Both the first and third argument can also be subqueries. A subquery is defined by passing a function and calling the selectFrom method of the object passed into the function:

    const persons = await db
    .selectFrom('person')
    .selectAll()
    .where(
    (qb) => qb.selectFrom('pet')
    .select('pet.name')
    .whereRef('pet.owner_id', '=', 'person.id')
    .limit(1),
    '=',
    'Fluffy'
    )
    .execute()

    The generated SQL (PostgreSQL):

    select *
    from "person"
    where (
    select "pet"."name"
    from "pet"
    where "pet"."owner_id" = "person"."id"
    limit $1
    ) = $2

    A where in query can be built by using the in operator and an array of values. The values in the array can also be subqueries or raw sql expressions.

    const persons = await db
    .selectFrom('person')
    .selectAll()
    .where('person.id', 'in', [100, 200, 300])
    .execute()

    The generated SQL (PostgreSQL):

    select * from "person" where "id" in ($1, $2, $3)
    

    If everything else fails, you can always use the sql tag as any of the arguments, including the operator:

    importsql } from 'kysely'

    const persons = await db
    .selectFrom('person')
    .selectAll()
    .where(
    sql`coalesce(first_name, last_name)`,
    'like',
    '%' + name + '%',
    )
    .execute()

    The generated SQL (PostgreSQL):

    select * from "person"
    where coalesce(first_name, last_name) like $1

    If you only pass one function argument to this method, it can be used to create parentheses around other where statements:

    const persons = await db
    .selectFrom('person')
    .selectAll()
    .where((qb) => qb
    .where('id', '=', 1)
    .orWhere('id', '=', 2)
    )
    .execute()

    The generated SQL (PostgreSQL):

    select * from "person" (where "id" = 1 or "id" = 2)
    

    In all examples above the columns were known at compile time (except for the raw sql expressions). By default kysely only allows you to refer to columns that exist in the database and can be referred to in the current query and context.

    Sometimes you may want to refer to columns that come from the user input and thus are not available at compile time.

    You have two options, the sql tag or db.dynamic. The example below uses both:

    importsql } from 'kysely'
    const { ref } = db.dynamic

    const persons = await db
    .selectFrom('person')
    .selectAll()
    .where(ref(columnFromUserInput), '=', 1)
    .orWhere(sql.id(columnFromUserInput), '=', 2)
    .execute()

    Type Parameters

    Parameters

    Returns SelectQueryBuilder<DB, TB, O>

  • Parameters

    • grouper: WhereGrouper<DB, TB>

    Returns SelectQueryBuilder<DB, TB, O>

  • Parameters

    Returns SelectQueryBuilder<DB, TB, O>

  • Adds a where exists clause to the query.

    You can either use a subquery or a raw sql snippet.

    Examples

    The query below selets all persons that own a pet named Catto:

    const petName = 'Catto'
    const persons = await db
    .selectFrom('person')
    .selectAll()
    .whereExists((qb) => qb
    .selectFrom('pet')
    .select('pet.id')
    .whereRef('person.id', '=', 'pet.owner_id')
    .where('pet.name', '=', petName)
    )
    .execute()

    The generated SQL (PostgreSQL):

    select * from "person"
    where exists (
    select "pet"."id"
    from "pet"
    where "person"."id" = "pet"."owner_id"
    and "pet"."name" = $1
    )

    The same query as in the previous example but with using raw sql:

    import { sql } from 'kysely'

    const petName = 'Catto'
    db.selectFrom('person')
    .selectAll()
    .whereExists(
    sql`(select pet.id from pet where person.id = pet.owner_id and pet.name = ${petName})`
    )

    The generated SQL (PostgreSQL):

    select * from "person"
    where exists (
    select pet.id
    from pet
    where person.id = pet.owner_id
    and pet.name = $1
    )

    Parameters

    Returns SelectQueryBuilder<DB, TB, O>

  • Adds a where clause where both sides of the operator are references to columns.

    The normal where method treats the right hand side argument as a value by default. whereRef treats it as a column reference. This method is expecially useful with joins and correlated subqueries.

    Examples

    Usage with a join:

    db.selectFrom(['person', 'pet'])
    .selectAll()
    .whereRef('person.first_name', '=', 'pet.name')

    The generated SQL (PostgreSQL):

    select * from "person", "pet" where "person"."first_name" = "pet"."name"
    

    Usage in a subquery:

    const persons = await db
    .selectFrom('person')
    .selectAll('person')
    .select((qb) => qb
    .selectFrom('pet')
    .select('name')
    .whereRef('pet.owner_id', '=', 'person.id')
    .limit(1)
    .as('pet_name')
    )
    .execute()

    The generated SQL (PostgreSQL):

    ```sql select "person".*, ( select "name" from "pet" where "pet"."owner_id" = "person"."id" limit $1 ) as "pet_name" from "person"

    Parameters

    Returns SelectQueryBuilder<DB, TB, O>

Generated using TypeDoc