KDB knowledge

SELECT

Choose the columns and values that a query gives back, and the table they come from.

SELECT reads data. You say which values you want (the select list), and from which table (FROM). Every other part (WHERE, GROUP BY, ORDER BY, ...) is optional and has its own help page.

A select item can be a column, a calculation, a function or a constant. Give it a name with AS.

Example: Today's change of every symbol, like a market summary (sample data: sample)

SELECT symbol, open, close,
       round(close - open, 2) AS change,
       round((close - open) / open * 100, 2) AS change_pct
FROM ochl_day
WHERE time IN '2026-09-10'
ORDER BY change_pct DESC;

Result:

symbol (SYMBOL)open (DOUBLE)close (DOUBLE)change (DOUBLE)change_pct (DOUBLE)
VOLT185.6191.25.63.02
CITY504.6504.90.30.06
COAST380.1376.1-4-1.05

(3 rows)

SELECT

Syntax:

SELECT [DISTINCT] item [[AS] alias], ...
[FROM source [JOIN ...]]
[WHERE condition]
[LATEST ON time PARTITION BY column, ...]
[SAMPLE BY interval ...]
[GROUP BY expression, ...]
[HAVING condition]
[UNION ALL SELECT ...]
[ORDER BY expression [ASC | DESC], ...]
[LIMIT n [OFFSET m]]

The parts must be written in this order. KDB does the work in another order:

StepPartWhat happens
1FROM, JOINread the tables
2WHEREkeep only the rows that match
3LATEST ONkeep the newest row of each group
4SAMPLE BY, GROUP BYmake groups and compute sum, max, ...
5HAVINGkeep only the groups that match
6window functionslag, sma, row_number, ...
7select list, DISTINCTcompute the output columns
8UNION ALLadd the rows of the next query
9ORDER BY, LIMIT, OFFSETsort and cut
ItemExample
a columnclose
a column of one table (with joins)f.symbol
a calculationhigh - low
a functionround(close, 1), upper(name)
an aggregatecount(*), max(high) (see GROUP BY)
a constant'hello', 100, TRUE, NULL
all columns*, f.*

Example: Trade log: the value of each trade on 2026-09-09 (sample data: sample)

SELECT transaction_id, symbol, quantity, rate, quantity * rate AS value
FROM trade_log
WHERE date IN '2026-09-09'
ORDER BY value DESC
LIMIT 4;

Result:

transaction_id (LONG)symbol (SYMBOL)quantity (LONG)rate (DOUBLE)value (DOUBLE)
100001TELCO1000881881000
100007TELCO1000879879000
100005CITY500517258500
100004CITY500514.5257250

(4 rows)

Example: App users: name, email and plan (sample data: query-app)

SELECT username, lower(email) AS email, upper(plan) AS plan
FROM app_users
WHERE id <= 4;

Result:

username (STRING)email (STRING)plan (STRING)
ramram.sharma@gmail.comPRO
sitasita.k@yahoo.comFREE
hari_99hari99@gmail.comFREE
gitagita.rai@gmail.comPRO

(4 rows)

Example: Accounting: the amount of each journal line, debit or credit (sample data: query-app)

SELECT line_id, entry_id, account, coalesce(debit, 0) - coalesce(credit, 0) AS amount, memo
FROM ledger
WHERE entry_id IN (2, 8);

Result:

line_id (INT)entry_id (INT)account (INT)amount (DECIMAL(2))memo (STRING)
321200257500.00Buy 500 CITY at 515
422000-257500.00Buy 500 CITY at 515
158110012600.00Sell 20 CITY at 630
1681200-10300.00Sell 20 CITY at 630
1784100-2300.00Sell 20 CITY at 630

(5 rows)

, table.

Syntax:

SELECT * FROM table
SELECT alias.*, other_item, ... FROM table alias JOIN ...

* means every column of every table in FROM, in table order. alias.* means every column of one table.

Example (sample data: sample)

SELECT * FROM brokers;

Result:

id (INT)name (STRING)
1Keystone Securities
34Vision Securities
45Imperial Securities
49Online Securities
58Northgate Securities

(5 rows)

Example: All columns of the trade, plus the buyer's name (sample data: sample)

SELECT f.*, b.name AS buyer_name
FROM trade_log f
JOIN brokers b ON b.id = f.buyer
WHERE f.transaction_id = 100017;

Result:

date (TIMESTAMP)transaction_id (LONG)symbol (SYMBOL)buyer (INT)seller (INT)quantity (LONG)rate (DOUBLE)amount (DOUBLE)buyer_name (STRING)
2026-09-10T00:00:00.000Z100017TELCO4934500881440500Online Securities

(1 row)

Example: * and count(*) do not mix (sample data: sample; shows an error)

SELECT *, count(*) FROM brokers;

Result:

Error: line 1, column 8: * cannot be combined with aggregates or SAMPLE BY

AS: column names

Syntax:

item AS alias
item alias
item AS "any name"

AS gives an output column a name. The word AS is optional.

WrittenColumn name
closeclose
close AS last_pricelast_price
close * 2 (no alias)close * 2
count(*) (no alias)count(*)
close AS "Close Price"Close Price (double quotes keep spaces and case)

Example (sample data: sample)

SELECT symbol, close AS last_price, close last, close * 2, round(close) AS "Close (whole dollars)"
FROM ochl_day
WHERE time IN '2026-09-10';

Result:

symbol (SYMBOL)last_price (DOUBLE)last (DOUBLE)close * 2 (DOUBLE)Close (whole dollars) (DOUBLE)
CITY504.9504.91009.8505
COAST376.1376.1752.2376
VOLT191.2191.2382.4191

(3 rows)

Example: Aggregates without an alias get their text as the name (sample data: sample)

SELECT symbol, count(*), max(high) AS highest
FROM ochl_day
GROUP BY symbol;

Result:

symbol (SYMBOL)count(*) (LONG)highest (DOUBLE)
CITY19546.2
COAST19429.9
VOLT19199.7

(3 rows)

Example: A missing comma quietly renames the column (sample data: sample)

SELECT symbol close FROM securities LIMIT 2;

Result:

close (SYMBOL)
ACME
CITY

(2 rows)

Example: A reserved word as a name needs double quotes (sample data: sample; shows an error)

SELECT symbol AS order FROM securities;

Result:

Error: line 1, column 18: expected an alias after AS but found the reserved word 'order' (write it in double quotes, "order", to use it as a name)

Example: The fix (sample data: sample)

SELECT symbol AS "order" FROM securities LIMIT 2;

Result:

order (SYMBOL)
ACME
CITY

(2 rows)

SELECT without FROM

Syntax:

SELECT expression [[AS] alias], ...

Without FROM, KDB computes the values once and gives one row. Use it like a calculator, or to test a function.

Example (sample data: sample)

SELECT 1 + 1 AS two, round(100000 * 1.08, 2) AS with_interest, upper('city') AS symbol;

Result:

two (LONG)with_interest (DOUBLE)symbol (STRING)
2108000CITY

(1 row)

Example: What is 11:00 Nepal time in UTC? (sample data: sample)

SELECT CAST('2026-09-10T11:00:00+05:45' AS TIMESTAMP) AS market_open_utc;

Result:

market_open_utc (TIMESTAMP)
2026-09-10T05:15:00.000Z

(1 row)

Example: * needs a table (sample data: sample; shows an error)

SELECT *;

Result:

Error: line 1, column 8: * needs a FROM table

FROM

Syntax:

FROM table [[AS] alias]
FROM database.table [[AS] alias]
FROM view [[AS] alias]
FROM (SELECT ...) [AS] alias

FROM names the table the rows come from. It can also be a view or a subquery in ( ).

PartMeaning
tablea relational or time-series table of the current database
database.tablea table of another database on the same server (see queries across databases)
aliasa short name for the table, used as alias.column (see table aliases)
(SELECT ...) aliasthe rows of another query; the alias is required

Example: A table with a short name (sample data: sample)

SELECT s.symbol, s.sector FROM securities AS s WHERE s.sector = 'Banking';

Result:

symbol (SYMBOL)sector (STRING)
CITYBanking
COASTBanking

(2 rows)

Example: Rows of a subquery: trades per symbol, only the busy ones (sample data: sample)

SELECT t.symbol, t.trades
FROM (SELECT symbol, count(*) AS trades FROM trade_log GROUP BY symbol) t
WHERE t.trades > 5;

Result:

symbol (SYMBOL)trades (LONG)
CITY11
COAST11
TELCO6

(3 rows)

Example: A wrong table name (sample data: sample; shows an error)

SELECT * FROM ochl_days;

Result:

Error: line 1, column 15: table or view 'ochl_days' does not exist

DISTINCT

Syntax:

SELECT DISTINCT item, ... FROM ...

DISTINCT removes repeated rows from the result. Two rows are the same when all their output columns are equal.

Example (sample data: sample)

SELECT DISTINCT sector FROM securities ORDER BY sector;

Result:

sector (STRING)
Banking
Energy
Investment
Telecom

(4 rows)

Example: Which broker bought which symbol on 2026-09-09 (sample data: sample)

SELECT DISTINCT buyer, symbol
FROM trade_log
WHERE date IN '2026-09-09'
ORDER BY buyer, symbol;

Result:

buyer (INT)symbol (SYMBOL)
1CITY
34CITY
34COAST
45CITY
49TELCO
58COAST
58TELCO

(7 rows)

Example: Cities of app users (NULL appears once) (sample data: query-app)

SELECT DISTINCT city FROM app_users ORDER BY city;

Result:

city (STRING)
Dharan
Kathmandu
Lalitpur
Pokhara
NULL

(5 rows)

Example: Count different values instead (sample data: sample)

SELECT count(DISTINCT symbol) AS symbols_traded, count(*) AS trades FROM trade_log;

Result:

symbols_traded (LONG)trades (LONG)
432

(1 row)