Query Basics
Every KSQL query starts with SELECT (or DESCRIBE) and follows standard SQL clause order:
SELECT ... FROM ... [WHERE ...] [GROUP BY ...] [HAVING ...] [ORDER BY ...] [LIMIT ...]
This page covers the basics. Joins and Grouping get their own pages.
SELECT
Specify which columns or expressions to return.
-- All columns
SELECT * FROM Customers
-- Specific columns
SELECT Name, Email, Revenue FROM Customers
-- With aliases (AS keyword)
SELECT Name AS customer_name, Revenue AS total_revenue FROM Customers
-- Implicit aliases (no AS keyword)
SELECT Name customer_name, Revenue total_revenue FROM Customers
-- Expressions in SELECT
SELECT Name, Revenue * 1.1 AS projected FROM Customers
You cannot mix * with other columns in the same SELECT:
-- This will error:
SELECT *, Name FROM Customers
-- Instead:
SELECT * FROM Customers
FROM
Specify the table to query. Table names are case-insensitive and must match a DataTable in your workspace.
FROM Customers
FROM customers -- same table (case-insensitive)
FROM Customers AS c -- with alias
FROM Customers c -- implicit alias
Every query requires a FROM clause (except DESCRIBE).
WHERE
Filter rows using conditions. KSQL supports all standard comparison operators plus logical combinators.
-- Equality
WHERE Status = 'active'
WHERE Status != 'churned'
-- Numeric comparisons
WHERE Revenue > 50000
WHERE Revenue >= 50000
WHERE Revenue <= 1000
-- Pattern matching
WHERE Name LIKE '%Tech%' -- contains "Tech"
WHERE Email LIKE '%@gmail.com' -- ends with @gmail.com
WHERE Name LIKE 'A%' -- starts with "A"
WHERE Name NOT LIKE '%test%' -- does not contain "test"
-- List membership
WHERE Status IN ('active', 'pending', 'trial')
WHERE Status NOT IN ('churned', 'cancelled')
-- Range
WHERE Revenue BETWEEN 10000 AND 50000
WHERE Revenue NOT BETWEEN 0 AND 100
-- Null checks
WHERE Website IS NULL
WHERE Website IS NOT NULL
-- Logical operators
WHERE Status = 'active' AND Revenue > 10000
WHERE Status = 'churned' OR Status = 'cancelled'
WHERE NOT Status = 'deleted'
-- Grouping with parentheses
WHERE (Status = 'active' OR Status = 'trial') AND Revenue > 5000
WHERE NOT (Status = 'churned' AND Revenue < 1000)
For tag/multi-select columns, see CONTAINS in Operators.
ORDER BY
Sort results by one or more columns or expressions.
-- Ascending (default)
ORDER BY Name ASC
ORDER BY Name -- ASC is the default
-- Descending
ORDER BY Revenue DESC
-- Multi-column sort
ORDER BY Status ASC, Revenue DESC
-- Sort by alias
SELECT Name, Revenue * 12 AS annual
FROM Customers
ORDER BY annual DESC
-- Sort by expression
ORDER BY UPPER(Name) ASC
LIMIT and OFFSET
Control the number of rows returned and where to start.
-- First 100 rows
LIMIT 100
-- Skip 50 rows, then return 100
LIMIT 100 OFFSET 50
-- MySQL-style syntax: LIMIT offset, count
LIMIT 50, 100 -- skip 50, return 100
-- Standalone OFFSET (must follow LIMIT)
LIMIT 200
OFFSET 100
Maximum result size is 1000 rows per query, regardless of the LIMIT value. Paginate with OFFSET for larger result sets.
DISTINCT
Remove duplicate rows from results.
-- Unique statuses
SELECT DISTINCT Status FROM Customers
-- Unique combinations
SELECT DISTINCT Region, Status FROM Customers
-- Count unique values
SELECT COUNT(DISTINCT Status) AS unique_statuses FROM Customers
DESCRIBE
View a table's schema (column names, types, and configuration).
DESCRIBE Customers
DESCRIBE "Order History" -- quoted for names with spaces
Returns a table showing each column's name, type, whether it's indexed, and any relevant configuration (options for dropdowns, linked tables for relations, etc.).