KDB knowledge

Rules

Name a check, the trading hours or the dedup choice of a table once, and KDB applies it to every row written - saying which rule refused a row and why.

A rule is a named check or setting of one table. It applies to every row written to the table - INSERT, UPDATE, COPY, /imp, /write and line protocol - and a row it refuses says which rule and why. Rules are listed by SHOW RULES, switched off and on by ALTER RULE, and saved with the table.

KindExampleWhat it does
checkCHECK (close > 0)every new or changed row must not make the condition false
sessionSESSION '11:00' TO '15:00' TIME ZONE 'Asia/Kathmandu' CALENDAR nepsethe row's time must be inside the hours, on a trading day of the calendar
settingSET dedup_keep = 'first'which of two rows with the same DEDUP KEY stays

CREATE RULE

Syntax:

CREATE RULE [IF NOT EXISTS] name ON table
    CHECK (condition)
  | SESSION 'HH:MM' TO 'HH:MM' [TIME ZONE 'zone'] [CALENDAR calendar]
  | SET dedup_keep = 'first' | 'last'
  [ON FAIL REJECT | SKIP] [MESSAGE 'text']
PartMeaning
CHECK (condition)a condition on the values of one row, as a CHECK constraint. A condition that is NULL passes (standard SQL): write close IS NOT NULL AND close > 0 to refuse a missing price
SESSION ... TO ...the row's time, on the clock of TIME ZONE (UTC when not given), from the first time to the second (both included). With CALENDAR, only on its trading days (calendars). The table needs a time column
ON FAIL REJECTthe default: the statement fails, and nothing of it is written (PostgreSQL code 23514)
ON FAIL SKIPthe row is left out and the statement goes on: the answer says ..., 1 left out by rules (ON FAIL SKIP). An UPDATE that would break the rule is refused instead (a row already there is never left out)
MESSAGE 'text'your words in the refusal, before the reason
SET dedup_keep = 'first'a row whose DEDUP KEY the table holds already is left out, whatever the write asked (also INSERT OR REPLACE and /write). 'last' is the default: the new row replaces the old one. The table needs a DEDUP KEY

Example: A price guard: the refused row names its rule (shows an error)

Setup:

CREATE TABLE ohlc (time TIMESTAMP, symbol SYMBOL, open DOUBLE, close DOUBLE) TIMESERIES(time) PARTITION BY DAY;
CREATE RULE price_guard ON ohlc CHECK (open > 0 AND close > 0) MESSAGE 'prices must be above 0';
INSERT INTO ohlc VALUES ('2026-10-01T05:30:00Z', 'NABIL', 500, 0);

Result:

Error: rule 'price_guard' of table 'ohlc' refused the row: prices must be above 0 (open > 0 AND close > 0 is false for the row open='500', close='0')

Example: ON FAIL SKIP leaves the bad row out and keeps the others

Setup:

CREATE TABLE ticks (time TIMESTAMP, symbol SYMBOL, price DOUBLE, qty DOUBLE) TIMESERIES(time) PARTITION BY DAY;
CREATE RULE no_negative_qty ON ticks CHECK (qty >= 0) ON FAIL SKIP;
INSERT INTO ticks VALUES ('2026-10-01T05:30:00Z', 'NABIL', 500, 10), ('2026-10-01T05:31:00Z', 'NABIL', 501, -3),
  ('2026-10-01T05:32:00Z', 'NABIL', 502, 7);

Result:

2 row(s) inserted, 1 left out by rules (ON FAIL SKIP)

Example: Trading hours of NEPSE: 11:00 to 15:00 in Kathmandu, on its trading days (shows an error)

Setup:

CREATE CALENDAR nepse_days (TIME ZONE 'Asia/Kathmandu', ERA FROM '2022-01-01' DAYS sun-thu);
CREATE TABLE trades (time TIMESTAMP, symbol SYMBOL, price DOUBLE) TIMESERIES(time) PARTITION BY DAY;
CREATE RULE nepse_hours ON trades SESSION '11:00' TO '15:00' TIME ZONE 'Asia/Kathmandu' CALENDAR nepse_days;
INSERT INTO trades VALUES ('2026-10-01T10:30:00Z', 'NABIL', 500);

Result:

Error: rule 'nepse_hours' of table 'trades' refused the row: its time 2026-10-01T16:15:00 Asia/Kathmandu is outside the session 11:00 to 15:00

ALTER RULE

Syntax:

ALTER RULE [IF EXISTS] name ENABLE | DISABLE | RENAME TO new_name

A disabled rule stays, and checks nothing until ENABLE.

DROP RULE

Syntax:

DROP RULE [IF EXISTS] name [, name ...]

See the rules: SHOW RULES

SHOW RULES is SELECT * FROM kdb_rules: one row per rule.

ColumnMeaning
rule, table_namethe rule and its table
kindcheck, session or set
definitionwhat follows ON table in its CREATE RULE
on_failreject or skip (empty for a setting)
message, enabledits message, and whether it is on

Example: All rules of the database

Setup:

CREATE TABLE quotes (time TIMESTAMP, symbol SYMBOL, bid DOUBLE, ask DOUBLE) TIMESERIES(time) PARTITION BY DAY;
CREATE RULE spread_ok ON quotes CHECK (ask >= bid) MESSAGE 'ask below bid';
SHOW RULES;

Result:

rule (STRING)table_name (STRING)kind (STRING)definition (STRING)on_fail (STRING)message (STRING)enabled (BOOL)
spread_okquotescheckCHECK (ask >= bid)rejectask below bidtrue

(1 row)