Skip to content

Querying kdb+ data

This page introduces the three things you need to query a kdb+ database: an endpoint to connect to, a tool to send the query from, and a query language to express it in.

To query a kdb+ database, you need:

  1. an endpoint - a q process that holds the data and listens for requests
  2. a client tool - the program you send the query from and view the result in
  3. a query language - typically qSQL, or a call to a function defined on the server

If the data is already in your local q process, you don't need an endpoint or a client: type the query at the q prompt. A client tool can still be useful, for example an IDE to edit queries and browse the results.

The examples on this page query a database of US equity trades and quotes. To build it, generate eight trading days of data into /tmp/testdb with the datagen module:

q)([getInMemoryTables; buildPersistedDB]): use `kx.datagen.capmkts
q)buildPersistedDB["/tmp/testdb"; ([start: 2026.04.01; end: 2026.04.10])]

Start a q process that loads the database and listens on port 5100:

q /tmp/testdb -p 5100

Endpoint

An endpoint is the host and port of a q process that listens on a port. The same port can accept several kinds of connection:

  • q IPC - the native binary protocol, used by q, PyKX, IDEs, and the client libraries. It's the fastest way to move data, because results travel in kdb+ format without conversion. See IPC basics.
  • HTTP - text requests from a browser, curl, or any HTTP client. See HTTP.
  • WebSocket - a persistent, full-duplex connection, commonly used by browser applications for streaming queries and updates. See WebSockets.

In production, clients often connect to a gateway rather than to the process that holds the data. The gateway routes each query to the right processes and combines the results.

Client tools

Pick a tool based on what you want to do with the result.

Another q process on your local computer

Open a handle to the endpoint and send a synchronous request. The result comes back as a q object, ready for further processing:

q)h:hopen `:localhost:5100  / or simply: hopen 5100
q)h "select from trade where date=last date, i<3"
date       sym  time                 price  size stop cond ex
-------------------------------------------------------------
2026.04.10 AAPL 0D09:30:00.207601090 307.12 84   0    C    X
2026.04.10 AAPL 0D09:30:00.631051656 307.15 68   0    X    D
2026.04.10 AAPL 0D09:30:00.719172601 307.16 64   1    H    S

This is how q processes in a distributed system talk to each other. See IPC basics and asynchronous communication.

Browser or curl

The built-in web server answers HTTP requests without extra software, which suits ad-hoc queries. Put the query after ? in the URL, and choose the response format with the path, for example .txt, .csv or .json:

$ curl --variable 'q=select max price by sym from trade where date=2026.04.10, sym in `AAPL`MSFT' \
    --expand-url 'http://localhost:5100/.csv?{{q:url}}'
sym,price
AAPL,312.43
MSFT,576.7

The query must be URL-encoded. Here --variable (curl 8.3 or later) stores the query in the curl variable q, and {{q:url}} inserts it into the URL with spaces and special characters encoded, so the query stays readable.

Don't use --data-urlencode

curl -G --data-urlencode encodes spaces as +, which the default q HTTP handler doesn't decode, so the query fails with a '+ error.

If the server exposes a REST API, call its endpoints in the same way. See HTTP to customize the request handlers and secure access.

Secure query endpoints

The default HTTP and IPC handlers can evaluate query text. Don't expose them to untrusted clients. In production, authenticate connections and restrict requests to an allowlist of server-defined functions; see Security and management.

IDE

An IDE designed for kdb+ lets you write queries, run them against a connection, and explore the result. Results are typically tables, and the IDE lets you sort by a column and filter rows by value without writing more q.

Jupyter notebook and PyKX

PyKX lets you query kdb+ from Python and convert results to pandas, Polars, PyArrow, or NumPy objects. Use it in a Jupyter notebook to combine kdb+ queries with Python analytics and plotting.

KX Dashboards

KX Dashboards builds interactive, feature-rich dashboards on top of kdb+ queries, with real-time updates, charts, grids, and drill-downs. Use it to share analysis with users who don't write q.

Query language

Whatever the tool, the server evaluates the request and returns the result. The request is typically either a function call or a qSQL statement.

Function call

A function defined on the server, also called a user-defined function (UDF), stored procedure or API, hides the query logic behind a name and a parameter list. For example, the server defines vwap to return the volume-weighted average price of some stocks on a given date:

q)vwap:{[d;s] select vwap:size wavg price by sym from trade where date=d, sym in s}

Clients call it by sending the function name and arguments as a list rather than as a string:

q)h (`vwap; 2026.04.10; `AAPL`MSFT)
sym | vwap
----| --------
AAPL| 304.9213
MSFT| 561.6922

Function calls are the preferred way to expose data in production:

  • The server controls which queries clients can run, so you can apply access control.
  • Arguments travel as typed q values, so you avoid building query strings and the injection risks that come with them.
  • You can change or optimize the implementation without changing the clients.

These benefits depend on server-side enforcement. Configure the message handlers to reject arbitrary query strings and dispatch only the functions each client is allowed to call.

qSQL

For ad-hoc analysis, write a qSQL statement. qSQL has a syntax similar to SQL and works on both in-memory and on-disk tables. There are four qSQL statements:

select

Returns a table: a subset of rows and columns, new computed columns, or aggregations. It's the statement you'll use most often. On a partitioned table, put the partition column (here date) first in the where clause so that q reads only the partitions it needs.

q)select n:count i, avgPrice:avg price by sym from trade where date=2026.04.10, sym in `AAPL`MSFT
sym | n    avgPrice
----| -------------
AAPL| 1048 304.9977
MSFT| 979  561.811
update

Adds new columns or overwrites existing ones. On a table mapped from disk, update returns a modified copy in memory and leaves the files unchanged.

q)3#update range:high-low from daily
date       sym  open   high   low    close  price       size  range
-------------------------------------------------------------------
2026.04.01 AAPL 254.96 277.22 253.52 276.85 1.36267e+07 50863 23.7
2026.04.01 AGEN 3.99   4.22   3.9    4.21   213204.7    52955 0.32
2026.04.01 AIG  79.8   82.58  78.75  82.19  4119636     51239 3.83
delete

Removes rows or columns. Like update, it returns a copy in memory, so the table on disk keeps all its rows:

q)count delete from daily where date<2026.04.10
51
q)count daily
408
exec

Returns its result in whatever shape the expression produces (a list, a dictionary, or an atom) rather than always a table. Use it for advanced cases, such as feeding a result directly into further q code.

q)exec sym!close from daily where date=2026.04.10, sym in `AAPL`MSFT
AAPL| 300.78
MSFT| 564.14
q)exec max high from daily where sym=`AAPL
322.98

Partitioned tables

On a partitioned table such as trade, only select runs directly. update and delete signal a par error, and exec signals nyi. Select the rows you need first, then apply the other statement to the result in memory:

q)exec avg price by sym from select from trade where date=2026.04.10, sym in `AAPL`MSFT
AAPL| 304.9977
MSFT| 561.811

To change the data on disk itself, see database maintenance.

Prefer SQL?

KDB-X also accepts SQL queries, and clients that speak the PostgreSQL protocol can connect through PG Wire.

Next steps

  • How to select data - choose columns, filter, group, sort, and keep queries fast, on in-memory and on-disk tables
  • Joins - combine rows from two tables, including as-of and window joins for time-series data
  • Functional qSQL - construct queries when column names, filters, or grouping are chosen at runtime