User tables
User tables in Deephaven are tables that exist within the Deephaven database that are part of a user namespace. Unlike tables in system namespaces, user tables can be created, modified, and deleted by users without administrative privileges. Once a user table has been added to the database, it can be retrieved using the historical or live table API. Additionally, user tables do not require you to deploy a schema manually. The schema is inferred from the table itself.
This guide covers what user tables are as well as how to add, modify, and delete them from Deephaven's database.
Types of user tables
There are several different types of user tables in Deephaven.
Partitioned
A partitioned user table is split into partitions by one or more partitioning columns. In practice, they are most often partitioned on a single column. The most common partitioning column used is a Date
column, for which each unique date has its own dataset. Partitioned user tables can have both direct and live partitions. Users must first add a schema before creating or adding data to a partitioned user table.
Unpartitioned
An unpartitioned user table is not split into partitions. Thus, the data for an unpartitioned user table is written to a single location in memory. All unpartitioned tables are direct.
Direct
A direct user table is managed directly on the filesystem by the query worker. Direct user tables cannot add, remove, or modify rows to pre-existing partitions, and do not update after retrieval. Direct user tables are considered historical data, and are therefore accessed via the historical table API. Direct user tables can be either partitioned or unpartitioned.
Live
Live user tables are managed centrally by the Deephaven system in Deephaven format. They are ingested and served similarly to system intraday data. These tables tick after retrieval. They are accessed using the live table API. All live user tables are partitioned.
Input
Input tables are a special type of user table where data can not only be added, modified, and removed programmatically, but also via the UI similar to a spreadsheet. For more information on input tables, see the Input table user guide.
Add, modify, and delete user tables
The Deephaven API allows user tables to be added, modified, and removed from the user namespace. The following sections provide examples of how to add, modify, and delete user tables.
Add user tables
Each of the following subsections deals with adding a user table of one of the previously mentioned types.
Unpartitioned
The following example adds an unpartitioned user table to the user namespace UserNamespace
.
tableToWrite = newTable(
doubleCol("Doubles", 3.1, 5.45, -1.0),
stringCol("Strings", "Creating", "New", "Tables")
)
// Add the unpartitioned table assuming table UserNamespace.MyTable does not exist
db.addUnpartitionedTable("UserNamespace", "MyTable", tableToWrite)
// Get the table from the namespace
fromDisk = db.historicalTable("UserNamespace", "MyTable")
from deephaven import new_table
from deephaven.column import string_col, double_col
table_to_write = new_table(
[
double_col("Doubles", [3.1, 5.45, -1.0]),
string_col("Strings", ["Creating", "New", "Tables"]),
]
)
# Add the unpartitioned table assuming table UserNamespace.MyTable does not exist
db.add_unpartitioned_table("UserNamespace", "MyTable", table_to_write)
# Get the table from the namespace
from_disk = db.historical_table("UserNamespace", "MyTable")
Partitioned
The following example writes the same table as the previous example as a partition to a partitioned user table. It first adds the schema for the partitioned user table before adding the partition.
import io.deephaven.engine.util.TableTools
// Create a table to write
tableToWrite = TableTools.newTable(
TableTools.doubleCol("Doubles", 3.1, 5.45, -1.0),
TableTools.stringCol("Strings", "Creating", "New", "Tables")
)
// Add the partitioned table schema
db.addPartitionedTableSchema("UserNamespace", "TableName", "Date", tableToWrite.getDefinition())
// Add a partition to the table
db.addTablePartition("UserNamespace", "TableName", "2023-01-01", tableToWrite)
// Read all partitions of the table back
fromDisk = db.historicalTable("UserNamespace", "TableName")
from deephaven import new_table
from deephaven.column import double_col, string_col
# Create a table to write
table_to_write = new_table(
[
double_col("Doubles", [3.1, 5.45, -1.0]),
string_col("Strings", ["Creating", "New", "Tables"]),
]
)
# Add the partitioned table schema
db.add_partitioned_table_schema("UserNamespace", "TableName", "Date", table_to_write)
# Add a partition to the table
db.add_table_partition("UserNamespace", "TableName", "2023-01-01", table_to_write)
# Read all partitions of the table back
from_disk = db.historical_table("UserNamespace", "TableName")
Modify user tables
Only partitioned user tables can be modified. Unpartitioned user tables must be deleted and re-added to "change" their data.
Update schema
There are two restrictions to updating the schema of a partitioned user table:
- You cannot change the type of an existing column
- You cannot change the partitioning column
The following example updates the schema of the partitioned user table TableName
in the user namespace UserNamespace
. Updating the schema returns a boolean value indicating whether the update occurred or if there was already an identical definition.
wasUpdated = db.updatePartitionedTableSchema("UserNamespace", "TableName", source.getDefinition())
was_updated = db.update_partitioned_table_schema("UserNamespace", "TableName", source)
Warning
Although each modification to a partitioned user table schema is verified for safety, multiple modifications are not guaranteed to be safe. For example, deleting a column, then adding it back with a new data type can result in unreadable data.
Add rows to a live partition
You can modify live partitions by adding data to them. The following example adds the rows from the source
table to the 2025-01-01
partition of user table TableName
found in the user namespace UserNamespace
:
ref = db.appendLiveTable(
"UserNamespace", "TableName", "2025-01-01", source
)
ref = db.append_live_table("UserNamespace", "TableName", "2025-01-01", source)
Additionally, the following example adds rows every time source
ticks. Doing so returns a reference that must be held onto to keep the operation active. When finished with the append, you can close the reference to stop appending and clean up any related resources.
ref = db.appendLiveTableIncremental(
"UserNamespace", "TableName", "2025-01-01", source
)
// Some time later when the append is finished
ref.close()
ref = db.append_live_table_incremental(
"UserNamespace", "TableName", "2025-01-01", source
)
# Some time later when the append is finished
ref.close()
Delete user tables
Unpartitioned
The following example deletes the unpartitioned user table TableName
from the user namespace UserNamespace
. Deleting an unpartitioned table returns a boolean value indicating whether or not the operation was successful.
wasDeleted = db.deleteUnpartitionedTable("UserNamespace", "TableName")
was_deleted = db.delete_unpartitioned_table("UserNamespace", "TableName")
Partitioned
The following example deletes the partitioned user table PartitionedTableName
from the user namespace UserNamespace
. Deleting a partitioned table returns a boolean value indicating whether or not the operation was successful.
wasDeleted = db.deletePartitionedTable("UserNamespace", "PartitionedTableName")
was_deleted = db.delete_partitioned_table("UserNamespace", "PartitionedTableName")
Caution
Deletions are permanent and cannot be recovered. Make 100% sure you want to delete a user table before doing so.
Individual partitions of a partitioned user table can be deleted, leaving all other partitions untouched. The following example deletes both the direct and live partition 2025-01-01
from the partitioned user table PartitionedTableName
in the user namespace UserNamespace
. Deleting a partition returns a boolean value indicating whether or not the operation was successful.
wasDeletedDirect = db.deleteTablePartition("UserNamespace", "PartitionedTableName", "2025-01-01")
wasDeletedLive = db.deleteLiveTablePartition("UserNamespace", "PartitionedTableName", "2025-01-01")
was_deleted_direct = db.delete_table_partition(
"UserNamespace", "PartitionedTableName", "2025-01-01"
)
was_deleted_live = db.delete_live_table_partition(
"UserNamespace", "PartitionedTableName", "2025-01-01"
)