KDB knowledge

Saved functions

Save a formula with a name, and use it in any query like a built-in function.

A saved function is a formula with a name. Its body is one expression (one formula, like (close - open) / open * 100). You write the formula once. Then every query can use it, like round or concat.

Example: The change of each share today, in percent (sample data: sample)

CREATE FUNCTION change_pct(price DOUBLE, prev DOUBLE) RETURNS DOUBLE
AS ((price - prev) / prev * 100);

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

Result:

CREATE FUNCTION change_pct(price DOUBLE, prev DOUBLE) RETURNS DOUBLE AS ((price - prev) / prev * 100

function 'change_pct' created

SELECT symbol, open, close, round(change_pct(close, open), 2) AS change FROM ochl_day WHERE time IN

symbol (SYMBOL)open (DOUBLE)close (DOUBLE)change (DOUBLE)
VOLT185.6191.23.02
CITY504.6504.90.06
COAST380.1376.1-1.05

(3 rows)

CREATE FUNCTION

Syntax:

CREATE [OR REPLACE] FUNCTION name(parameter TYPE, ...) [RETURNS TYPE] AS (expression)
CREATE [OR REPLACE] FUNCTION name() [RETURNS TYPE] AS (expression)

Saves a new function. OR REPLACE changes a function that already exists.

PartMeaning
namethe name of the function. Upper and lower case are the same (Tax and tax are one function).
parameter TYPEan input value and its type (INT, DOUBLE, DECIMAL(2), STRING, TIMESTAMP, ...). Write () for a function without inputs.
RETURNS TYPEoptional. The result is changed to this type (like CAST). Without it, the result keeps the type of the expression.
AS (expression)the body: one expression in brackets. It can use the parameters, operators, CASE, built-in functions and other saved functions.

Example: VAT of 13% on an amount of money, exact to the cent

CREATE FUNCTION vat(amount DECIMAL(2)) RETURNS DECIMAL(2) AS (round(amount * 0.13, 2));

SELECT vat(1000) AS on_1000, vat(99.99) AS on_99_99, 99.99 + vat(99.99) AS total;

Result:

CREATE FUNCTION vat(amount DECIMAL(2)) RETURNS DECIMAL(2) AS (round(amount * 0.13, 2))

function 'vat' created

SELECT vat(1000) AS on_1000, vat(99.99) AS on_99_99, 99.99 + vat(99.99) AS total

on_1000 (DECIMAL(2))on_99_99 (DECIMAL(2))total (DECIMAL(2))
130.0013.00112.99

(1 row)

Example: One function uses another: up, down or flat days (sample data: sample)

CREATE FUNCTION change_pct(price DOUBLE, prev DOUBLE) RETURNS DOUBLE
AS ((price - prev) / prev * 100);

CREATE FUNCTION move(price DOUBLE, prev DOUBLE) RETURNS STRING
AS (CASE WHEN change_pct(price, prev) > 0.5 THEN 'up'
         WHEN change_pct(price, prev) < -0.5 THEN 'down'
         ELSE 'flat' END);

SELECT move(close, open) AS move, count(*) AS days
FROM ochl_day
WHERE symbol = 'CITY'
GROUP BY move(close, open)
ORDER BY move;

Result:

CREATE FUNCTION change_pct(price DOUBLE, prev DOUBLE) RETURNS DOUBLE AS ((price - prev) / prev * 100

function 'change_pct' created

CREATE FUNCTION move(price DOUBLE, prev DOUBLE) RETURNS STRING AS (CASE WHEN change_pct(price, prev)

function 'move' created

SELECT move(close, open) AS move, count(*) AS days FROM ochl_day WHERE symbol = 'CITY' GROUP BY move

move (STRING)days (LONG)
down4
flat13
up2

(3 rows)

Example: Change a function with OR REPLACE

CREATE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (amount * 0.004);
SELECT fee(100000) AS old_fee;

CREATE OR REPLACE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (greatest(amount * 0.0036, 10));
SELECT fee(100000) AS new_fee, fee(1000) AS small_trade;

Result:

CREATE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (amount * 0.004)

function 'fee' created

SELECT fee(100000) AS old_fee

old_fee (DOUBLE)
400

(1 row)

CREATE OR REPLACE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (greatest(amount * 0.0036, 10))

function 'fee' replaced

SELECT fee(100000) AS new_fee, fee(1000) AS small_trade

new_fee (DOUBLE)small_trade (DOUBLE)
36010

(1 row)

Example: The name is already used (shows an error)

CREATE FUNCTION fee(amount DOUBLE) AS (amount * 0.004);
CREATE FUNCTION fee(amount DOUBLE) AS (amount * 0.0036);

Result:

function 'fee' created

Error: function 'fee' already exists; use CREATE OR REPLACE FUNCTION to change it

Example: RETURNS DECIMAL(2) with too many decimals (shows an error)

CREATE FUNCTION with_vat(amount DOUBLE) RETURNS DECIMAL(2) AS (amount * 1.13);
SELECT with_vat(99.99);

Result:

function 'with_vat' created

Error: line 2, column 8: cannot convert '112.98869999999998' to DECIMAL(2): 112.98869999999998 has more than 2 decimal places

Using a saved function

Syntax:

SELECT name(argument, ...) ... FROM ... WHERE name(...) ... GROUP BY name(...) ORDER BY name(...)

Call a saved function like a built-in one: its name and the arguments in brackets. It works in SELECT, WHERE, GROUP BY, ORDER BY, in views, in procedures and in triggers.

Example: Big trades only: a function in WHERE (sample data: sample)

CREATE FUNCTION trade_value(quantity LONG, rate DOUBLE) RETURNS DOUBLE AS (quantity * rate);

SELECT transaction_id, symbol, quantity, rate, trade_value(quantity, rate) AS value
FROM trade_log
WHERE trade_value(quantity, rate) >= 250000
ORDER BY value DESC;

Result:

CREATE FUNCTION trade_value(quantity LONG, rate DOUBLE) RETURNS DOUBLE AS (quantity * rate)

function 'trade_value' created

SELECT transaction_id, symbol, quantity, rate, trade_value(quantity, rate) AS value FROM trade_log W

transaction_id (LONG)symbol (SYMBOL)quantity (LONG)rate (DOUBLE)value (DOUBLE)
100001TELCO1000881881000
100007TELCO1000879879000
100017TELCO500881440500
100031COAST1000402402000
100015COAST1000398398000
100005CITY500517258500
100018CITY500516258000
100004CITY500514.5257250
100003CITY500513256500

(9 rows)

Example: A view uses the newest body of the function

CREATE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (amount * 0.004);
CREATE VIEW fee_on_lakh AS SELECT fee(100000) AS fee;
SELECT * FROM fee_on_lakh;

CREATE OR REPLACE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (amount * 0.0036);
SELECT * FROM fee_on_lakh;

Result:

CREATE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (amount * 0.004)

function 'fee' created

CREATE VIEW fee_on_lakh AS SELECT fee(100000) AS fee

view 'fee_on_lakh' created

SELECT * FROM fee_on_lakh

fee (DOUBLE)
400

(1 row)

CREATE OR REPLACE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (amount * 0.0036)

function 'fee' replaced

SELECT * FROM fee_on_lakh

fee (DOUBLE)
360

(1 row)

Example: Wrong number of arguments (shows an error)

CREATE FUNCTION change_pct(price DOUBLE, prev DOUBLE) RETURNS DOUBLE AS ((price - prev) / prev * 100);
SELECT change_pct(110);

Result:

function 'change_pct' created

Error: line 2, column 8: function 'change_pct' takes 2 argument(s) (price DOUBLE, prev DOUBLE), got 1

Example: Not in a computed column (shows an error)

CREATE FUNCTION trade_value(quantity LONG, rate DOUBLE) RETURNS DOUBLE AS (quantity * rate);
CREATE TABLE trades (quantity LONG, rate DOUBLE, value DOUBLE AS (trade_value(quantity, rate)));

Result:

function 'trade_value' created

Error: computed column 'value' cannot use the saved function 'trade_value'; computed columns can use built-in functions only

Rules for the body

Syntax:

AS (expression using only the parameters)

The body is checked when you create the function. These things are refused:

Not allowedWhyWhat to do
a column of a tablethe function does not know any tablegive the column as an argument: f(close)
a subquery (SELECT ...), EXISTS, IN (SELECT ...)a function works on one rowuse a procedure or a view
aggregates (sum, avg, ...) and window functions (sma, lag, ...)they need many rowscall them around the function: sum(f(x))
*
the name of a built-in function (round, pct_change, ...)the name is already takenchoose another name
calling itself (also through another function)it would never end
more than 16 levels of functions calling functions

Example: A built-in name (shows an error)

CREATE FUNCTION pct_change(price DOUBLE, prev DOUBLE) AS ((price - prev) / prev * 100);

Result:

Error: 'pct_change' is a built-in function; choose another name for the function

Example: A column that is not a parameter (shows an error)

CREATE FUNCTION day_range(high DOUBLE) AS (high - low);

Result:

Error: the body of function 'day_range' uses low, which is not one of its parameters (high DOUBLE); a function can only use its parameters

Example: An aggregate inside the body (shows an error)

CREATE FUNCTION total(x DOUBLE) AS (sum(x));

Result:

Error: the body of function 'total' cannot use 'sum': aggregate and window functions work on many rows (call them around the function instead)

Example: A subquery inside the body (shows an error)

CREATE FUNCTION last_close(s STRING) AS ((SELECT last(close) FROM ochl_day WHERE symbol = s));

Result:

Error: the body of function 'last_close' cannot use a subquery

Example: Two functions that call each other (shows an error)

CREATE FUNCTION a(x DOUBLE) AS (x + 1);
CREATE FUNCTION b(x DOUBLE) AS (a(x) * 2);
CREATE OR REPLACE FUNCTION a(x DOUBLE) AS (b(x));

Result:

CREATE FUNCTION a(x DOUBLE) AS (x + 1)

function 'a' created

CREATE FUNCTION b(x DOUBLE) AS (a(x) * 2)

function 'b' created

Error: in function 'a': in function 'b': function 'a' calls itself (a -> b -> a); a saved function cannot call itself

DROP FUNCTION

Syntax:

DROP FUNCTION [IF EXISTS] name

Removes a saved function.

Example

CREATE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (amount * 0.004);
DROP FUNCTION fee;
DROP FUNCTION IF EXISTS fee;

Result:

CREATE FUNCTION fee(amount DOUBLE) RETURNS DOUBLE AS (amount * 0.004)

function 'fee' created

DROP FUNCTION fee

function 'fee' dropped

DROP FUNCTION IF EXISTS fee

function 'fee' does not exist

Example: A function that used the dropped one fails when it runs (shows an error)

CREATE FUNCTION a(x DOUBLE) AS (x + 1);
CREATE FUNCTION b(x DOUBLE) AS (a(x) * 2);
DROP FUNCTION a;
SELECT b(1);

Result:

CREATE FUNCTION a(x DOUBLE) AS (x + 1)

function 'a' created

CREATE FUNCTION b(x DOUBLE) AS (a(x) * 2)

function 'b' created

DROP FUNCTION a

function 'a' dropped

Error: line 4, column 8: in function 'b': unknown function 'a'

Example: Without IF EXISTS, a missing name is an error (shows an error)

DROP FUNCTION no_such_function;

Result:

Error: function 'no_such_function' does not exist

SHOW FUNCTIONS

Syntax:

SHOW FUNCTIONS

Lists the saved functions of the database, in name order.

ColumnMeaning
namethe function name
argumentsthe parameters and their types
returnsthe RETURNS type, or NULL when there is none
definitionthe whole CREATE FUNCTION statement

Example

CREATE FUNCTION change_pct(price DOUBLE, prev DOUBLE) RETURNS DOUBLE AS ((price - prev) / prev * 100);
CREATE FUNCTION vat(amount DECIMAL(2)) RETURNS DECIMAL(2) AS (round(amount * 0.13, 2));
CREATE FUNCTION greeting(name STRING) AS (concat('Namaste, ', name));
SHOW FUNCTIONS;

Result:

CREATE FUNCTION change_pct(price DOUBLE, prev DOUBLE) RETURNS DOUBLE AS ((price - prev) / prev * 100

function 'change_pct' created

CREATE FUNCTION vat(amount DECIMAL(2)) RETURNS DECIMAL(2) AS (round(amount * 0.13, 2))

function 'vat' created

CREATE FUNCTION greeting(name STRING) AS (concat('Namaste, ', name))

function 'greeting' created

SHOW FUNCTIONS

name (STRING)arguments (STRING)returns (STRING)definition (STRING)
change_pctprice DOUBLE, prev DOUBLEDOUBLECREATE FUNCTION change_pct(price DOUBLE, prev DOUBLE) RETURNS DOUBLE AS ((price - prev) / prev * 100)
greetingname STRINGNULLCREATE FUNCTION greeting(name STRING) AS (concat('Namaste, ', name))
vatamount DECIMAL(2)DECIMAL(2)CREATE FUNCTION vat(amount DECIMAL(2)) RETURNS DECIMAL(2) AS (round(amount * 0.13, 2))

(3 rows)