Skip to content

SQL Query Building

Standard routes automatically generate SQL based on your configuration. This page covers all the components that make up a SQL query.

The primary table this route queries. Determines which columns are available for filtering and response mapping.

Example: For a user profile endpoint, the base table would be user.


Combine data from related tables to include information from multiple tables in your response.

PropertyDescription
TableThe related table to join
Local ColumnThe foreign key column in your base (or joined) table
Foreign ColumnThe column in the related table (typically id)
TypeJoin type: INNER or LEFT
AliasShort name for referencing joined columns
TypeDescription
INNEROnly returns rows where matching records exist in both tables
LEFTReturns all rows from the left table, with NULL for non-matching right table rows

When to use INNER:

  • When the relationship is required (e.g., every order must have a user)
  • When you only want results where both sides exist

When to use LEFT:

  • When the relationship is optional (e.g., a user might not have a manager)
  • When you want all base table rows regardless of whether related data exists

Aliases follow the format: {localColumn}_{foreignTable}

Example: Joining user.companyId to company.id creates alias companyId_company

This allows you to reference the joined table’s columns:

  • companyId_company.name → Company name
  • companyId_company.address → Company address

Base table: order

Join configuration:

Table: user
Local Column: order.userId
Foreign Column: user.id
Type: INNER
Alias: userId_user

Generated SQL:

SELECT ...
FROM "order"
INNER JOIN "user" AS "userId_user" ON "order"."userId" = "userId_user"."id"

Now you can use userId_user.firstName, userId_user.email, etc. in your response properties.


Filter which rows are returned or affected by your query.

PropertyDescription
TableThe table containing the column to filter
ColumnThe column to compare
OperatorThe comparison type
ValueThe value to compare against (can use $param or #global)
ConjunctionLogical connector to previous condition (AND or OR)
CustomRaw SQL expression (alternative to column-based filter)
OperatorDescriptionExample
=Equalsuser.id = $id
!=Not equalsstatus != 'deleted'
<Less thanprice < $maxPrice
>Greater thancreatedOn > $since
<=Less than or equalquantity <= $max
>=Greater than or equalage >= 18
LIKEPattern match (use % wildcard)name LIKE $search
NOT LIKENegative pattern matchemail NOT LIKE '%test%'
INMatch any value in setstatus IN $statuses
NOT INExclude values in setrole NOT IN ('guest')
STARTS WITHString prefix matchname STARTS WITH $prefix
ENDS WITHString suffix matchemail ENDS WITH $domain
ISIdentity comparisondeletedOn IS NULL
IS NOTNegative identitymanager IS NOT NULL

Simple equality:

Table: user
Column: id
Operator: =
Value: $userId

Pattern matching:

Table: user
Column: email
Operator: LIKE
Value: %$searchTerm%

Status filtering:

Table: order
Column: status
Operator: IN
Value: $statuses

Date range:

Table: order
Column: createdOn
Operator: >=
Value: $startDate
Conjunction: AND
Table: order
Column: createdOn
Operator: <=
Value: $endDate

Custom SQL:

Custom: "user"."firstName" || ' ' || "user"."lastName" LIKE $fullName

Sort query results (available for ARRAY and PAGED types).

PropertyDescription
TableTable containing the sort column
ColumnColumn to sort by
OrderDirection: ASC or DESC

Sort by creation date (newest first):

Table: order
Column: createdOn
Order: DESC

Sort by name (alphabetical):

Table: user
Column: lastName
Order: ASC

Multiple sort columns:

1. Table: user, Column: lastName, Order: ASC
2. Table: user, Column: firstName, Order: ASC

Aggregate rows by a column value.

PropertyDescription
TableTable containing the group column
ColumnColumn to group by

Base table: order

Group by: order.userId

Response properties:

  • userIdorder.userId
  • orderCountCOUNT(*)

Generated SQL:

SELECT "order"."userId", COUNT(*) as "orderCount"
FROM "order"
GROUP BY "order"."userId"

Value mappings for INSERT/UPDATE operations (POST, PUT, PATCH methods).

PropertyDescription
NameThe column name to assign a value to
ValueThe value to assign (can use $param or #global)

Create user (POST):

firstName = $firstName
lastName = $lastName
email = $email
companyId = #companyId
createdOn = now()

Update user status (PATCH):

status = $status
modifiedOn = now()

Set ownership (POST):

userId = #userId
companyId = #companyId

Nested queries within a response that fetch related data from another table.

PropertyDescription
TableThe related table to query
JoinsAdditional joins within the subquery
WhereConditions to filter subquery results
PropertiesFields to return from the subquery
Group ByOptional grouping
Order ByOptional sorting

Base table: user

Response properties:

  • iduser.id
  • nameuser.firstName
  • orders → Subquery

Subquery configuration:

Table: order
Where: order.userId = user.id
Properties:
- id → order.id
- total → order.total
- status → order.status
Order By: order.createdOn DESC

Response:

{
"data": {
"id": 1,
"name": "John",
"orders": [
{ "id": 101, "total": "299.99", "status": "completed" },
{ "id": 102, "total": "149.99", "status": "pending" }
]
}
}

Endpoint: Get user profile with company and recent orders

Base table: user

Joins:

Table: company
Local: user.companyId
Foreign: company.id
Type: LEFT
Alias: companyId_company

Where clauses:

user.id = $userId
AND user.status != 'deleted'

Response properties:

id → user.id
firstName → user.firstName
lastName → user.lastName
email → user.email
companyName → companyId_company.name
orders → [subquery]

Subquery (orders):

Table: order
Where: order.userId = user.id
Order By: order.createdOn DESC
Limit: 5
Properties:
- id → order.id
- total → order.total
- status → order.status
- createdOn → order.createdOn