title description
Create my first database Guide showing how to insert, query and delete rows in the context of time series data.

The goal of this guide is to explore QuestDB’s features to interact with time series data. This assumes you have an instance running. You can find guides to setup QuestDB on the introduction page.

In this tutorial, you will learn how to

As an example, we will look at hypothetical temperature readings from a variety of sensors.

:::info

All commands are run through the Web Console accessible at http://localhost:9000.

You can also run the same SQL via the Postgres endpoint or the REST API.

:::

Creating a table

The first step is to create tables. One will contain the metadata of our sensors, the other will contain the readings from these sensors.

Let’s start by creating the sensors table:


1. CREATE TABLE sensors (ID LONG, make STRING, city STRING);

For more information about this statement, please refer to the CREATE TABLE reference documentation.

Inserting data

Let’s populate our sensors table with procedurally-generated data:


1. INSERT INTO sensors
2. SELECT
3. x ID, --increasing integer
4. rnd_str('Eberle', 'Honeywell', 'Omron', 'United Automation', 'RS Pro') make,
5. rnd_str('New York', 'Miami', 'Boston', 'Chicago', 'San Francisco') city
6. FROM long_sequence(10000) x
7. ;

For more information about this statement, please refer to the INSERT reference documentation. About the functions, please refer to the random generator and the row generator pages.

Our sensors table now contains 10,000 randomly generated sensor values of different makes and in various cities. It should look like the table below:

ID make city
1 RS Pro New York
2 Honeywell Chicago
3 United Automation Miami
4 Honeywell Chicago

Let’s now create some sensor readings. In this case, we will create the table and generate the data at the same time:


1. CREATE TABLE readings
2. AS(
3. SELECT
4. x ID,
5. timestamp_sequence(to_timestamp('2019-10-17T00:00:00', 'yyyy-MM-ddTHH:mm:ss'), rnd_long(1,10,2) * 100000L) ts,
6. rnd_double(0)*8 + 15 temp,
7. rnd_long(0, 10000, 0) sensorId
8. FROM long_sequence(10000000) x)
9. TIMESTAMP(ts)
10. PARTITION BY MONTH;

The query above demonstrates how to use the following features:

  • TIMESTAMP(ts) elects the ts column as a designated timestamp. This enables partitioning tables by time.
  • PARTITION BY MONTH creates a monthly partitioning strategy where the stored data is effectively sharded by month.

The generated data will look like the following:

ID ts temp sensorId
1 2019-10-17T00:00:00.000000Z 19.37373911 9160
2 2019-10-17T00:00:00.600000Z 21.91184617 9671
3 2019-10-17T00:00:01.400000Z 16.58367834 8731
4 2019-10-17T00:00:01.500000Z 16.69308815 3447
5 2019-10-17T00:00:01.600000Z 19.67991569 7985

Running queries

Let’s select all records from the readings table (note that SELECT * FROM is optional in QuestDB):


1. readings;

Let’s also select the count of records from readings:


1. SELECT count() FROM readings;

count
10,000,000

and the average reading:


1. SELECT avg(temp) FROM readings;

average
18.999217780895

We can now leverage our sensors table to get more interesting data:


1. SELECT *
2. FROM readings
3. JOIN(
4. SELECT ID sensId, make, city
5. FROM sensors)
6. ON readings.sensorId = sensId;

The results should look like the table below:

ID ts temp sensorId sensId make city
1 2019-10-17T00:00:00.000000Z 16.472200460982 3211 3211 Omron New York
2 2019-10-17T00:00:00.100000Z 16.598432033599 2319 2319 Honeywell San Francisco
3 2019-10-17T00:00:00.100000Z 20.293681747009 8723 8723 Honeywell New York
4 2019-10-17T00:00:00.100000Z 20.939263119843 885 885 RS Pro San Francisco
5 2019-10-17T00:00:00.200000Z 19.336660059029 3200 3200 Honeywell San Francisco
6 2019-10-17T00:00:01.100000Z 20.946643576954 4053 4053 Honeywell Miami

1. SELECT city, max(temp)
2. FROM readings
3. JOIN(
4. SELECT ID sensId, city
5. FROM sensors) a
6. ON readings.sensorId = a.sensId;

The results should look like the table below:

city max
New York 22.999998786398
San Francisco 22.999998138348
Miami 22.99999994818
Chicago 22.999991705861
Boston 22.999999233377

1. SELECT ts, city, make, avg(temp)
2. FROM readings timestamp(ts)
3. JOIN
4. (SELECT ID sensId, city, make
5. FROM sensors
6. WHERE city='Miami' AND make='Omron') a
7. ON readings.sensorId = a.sensId
8. WHERE ts ='2019-10-21;1d' -- this is an interval between 21-10 and 1 day later

The results should look like the table below:

ts city make average
2019-10-21T00:00:44.600000Z Miami Omron 20.004285872098
2019-10-21T00:00:52.400000Z Miami Omron 16.68436714013
2019-10-21T00:01:05.400000Z Miami Omron 15.243684089291
2019-10-21T00:01:06.100000Z Miami Omron 17.193984104315
2019-10-21T00:01:07.100000Z Miami Omron 20.778686822666

For more information about these statements, please refer to the SELECT and JOIN pages.

Deleting tables

Upon dropping the table, all data is deleted:


1. DROP TABLE readings;
2. DROP TABLE sensors;