CQL data types
Data type is declared and enforced for each column in a table. It is important that you choose an appropriate type for the data you are storing.
BLOB type
The blob type stores binary data as Binary Large Objects (BLOBs) of arbitrary bytes (no validation).
Values are hexadecimal constants in the format 0xhex or 0Xhex where hex is one or more hex characters ([0-9,a-f,A-F]).
For example, 0x0000cafe3.
BLOBs are suitable for small binary payloads (small images or short strings). Storing large BLOBs, such as images or videos, can lead to unbalanced partitions and degraded performance. Therefore, the practical limit and recommended size for BLOBs is less than 1 MB, despite the maximum theoretical size of 2 GB.
|
For large binary content, store the data in an object store or content delivery network (CDN), and then store the URI in your database instead. |
You can use functions to convert between native types and BLOBs.
Boolean type
The boolean type represents a true or false value.
Stored internally as true or false, regardless of the original form used for INSERT or UPDATE.
When inserting or updating, values are case insensitive and not quoted.
When using the CQL shell COPY TO command to import or export data, you can change the format using the boolstyle option.
For example, when importing survey results that have a column of yes/no responses.
Counter
The counter type is used exclusively to store numbers that are updated by increments or decrements, such as page views, games played, or units in inventory.
Counter values are 64-bit signed integers that can only be incremented or decremented.
counter columns have the following limitations:
-
You cannot directly set the value of a counter with
INSERTorUPDATE … SET. Instead, you must increment or decrement counter values using theUPDATEcommand with the+or-operator. -
A
countercolumn cannot be part of aPRIMARY KEY. -
Tables with
countercolumns can have onlycountercolumns andPRIMARY KEYcolumns. -
You cannot create indexes on
countercolumns. -
countercolumns must be set when creating a table. You cannot useALTER TABLEto add acounterto an existing table. If you drop acountercolumn; you cannot useALTER TABLEto re-create the dropped column. -
You cannot set counter values to expire with
USING TTL. -
You cannot set the write time for counter columns with
USING TIMESTAMP. -
If nodes go down or writes fail, counter values can be inaccurate because counter operations are non-idempotent and cannot be retried implicitly. Retrying can result in an overcount, but not retrying can result in an undercount, so additional logic must be defined to handle counter write failures and data reconciliation.
Counter-related settings can be set in cassandra.yaml.
The following example creates a table with a counter column, and then increments and decrements the value using the UPDATE command with + and - operators:
-
Create a table that includes only the primary key (one or more columns) and one or more
countercolumns:CREATE TABLE IF NOT EXISTS cycling.popular_count ( id UUID PRIMARY KEY, popularity counter ); -
Use a
BATCHstatement to change the value of thepopularitycolumn. Operations are applied sequentially.-
Increment by 1
-
Increment by 125
-
Decrement by 64
BEGIN COUNTER BATCH UPDATE cycling.popular_count SET popularity = popularity + 1 WHERE id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47; UPDATE cycling.popular_count SET popularity = popularity + 125 WHERE id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47; UPDATE cycling.popular_count SET popularity = popularity - 64 WHERE id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47; APPLY BATCH; -
-
Use a single
UPDATEcommand to increment the value of thepopularitycolumn by 2, and use theWHEREclause to specify the row to update.UPDATE cycling.popular_count SET popularity = popularity + 2 WHERE id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47; -
Check the value of the counter column after all previous updates:
SELECT * FROM cycling.popular_count;The current value is 64, which is the result of the sequential increments and decrements (
0 + 1 + 125 - 64 + 2):id | popularity --------------------------------------+------------ 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47 | 64 (1 rows)
DseExecutorStateType
DseExecutorStateType is a reserved type used for Apache Spark™ clients on DSE Analytics nodes.
Geospatial types
Geospatial types are useful for storing data that is geometric in nature.
|
Geospatial type names are case sensitive. Enclose the type name in single quotes when creating a table. |
| Type | Description |
|---|---|
|
Contains two coordinate values for latitude and longitude. |
|
Comma-separated list of points. |
|
Set of two linestrings. |
Numeric types
|
Numeric types store values of different precision.
Choose types that are appropriately precise for the values you need to store.
For example, don’t use |
Enter numeric types in plain text in the INSERT, UPDATE, and the SELECT statement WHERE clause.
For example, age = 31.
Integers
| Type | Constants supported | Description |
|---|---|---|
|
integers |
8-bit signed integer |
|
integers |
16-bit signed integer |
|
integers |
32-bit signed integer |
|
integers |
64-bit signed integer |
|
integers |
Arbitrary-precision integer Maps to Java type |
Decimals
The default decimal separator is a period (.).
You can change the decimal separator in the driver settings, or with the decimalsep option when using the COPY command.
Internally, the decimal separator is stored as a period.
| Type | Constants supported | Description | ||
|---|---|---|---|---|
|
integers, floats |
Variable-precision decimal Supports integers and floats.
Maps to Java type |
||
|
integers, floats |
32-bit IEEE-754 floating point Maps to Java type |
||
|
integers, floats |
64-bit IEEE-754 floating point Maps to Java type |
Static keyword
static isn’t a distinct data type.
It is a modifier that can be applied to a column of any type.
Static columns apply the same value to all rows in a partition. The columns is static in every partition, but each partition can have a different value that is applied to the rows in that specific partition.
The table must have clustering columns to define static columns.
Only non-clustering columns can be marked static, and a static column cannot be part of the partition key.
Static columns are updated in a similar way to other columns: Specify the new value in your INSERT or UPDATE statement.
The new value is applied to all rows in the partition.
For example:
-
Create a table
cycling.country_flagwith a primary key consisting of the columnscountryandcyclist_name. Theflagcolumn is defined as aSTATICcolumn.CREATE TABLE IF NOT EXISTS cycling.country_flag ( country text, cyclist_name text, flag int STATIC, PRIMARY KEY (country, cyclist_name) ); -
Insert some data into the table.
INSERT INTO cycling.country_flag ( country, cyclist_name, flag ) VALUES ( 'Belgium', 'Jacques', 1 ); INSERT INTO cycling.country_flag ( country, cyclist_name ) VALUES ( 'Belgium', 'Andre' ); INSERT INTO cycling.country_flag ( country, cyclist_name, flag ) VALUES ( 'France', 'Andre', 2 ); INSERT INTO cycling.country_flag ( country, cyclist_name, flag ) VALUES ( 'France', 'George', 3 );Note that the
flagcolumn is entered with the same value for each row in the partition. -
Query the table to see the data.
SELECT * FROM cycling.country_flag;country | cyclist_name | flag ---------+--------------+------ Belgium | Andre | 1 Belgium | Jacques | 1 France | Andre | 3 France | George | 3 (4 rows)
A batch update can be used to update the static column value for all rows in the partition.
DISTINCT keyword
For tables that use static columns, the unique partition key identifiers for rows can be retrieved using the DISTINCT keyword.
Use the DISTINCT keyword to select static columns.
In this case, the database retrieves only the beginning (static column) of the partition.
SELECT DISTINCT country FROM cycling.country_flag;
country
---------
Belgium
France
(2 rows)
String and text types
|
Don’t use string types when another type is more appropriate.
For example, don’t use strings to store numbers, and don’t use |
Wrap strings in single quotes or double dollar signs ($$) in INSERT, UPDATE, and the SELECT statement WHERE clause.
For values that contain single quotes, `, or reserved characters, you must use additional escaping or change the wrapping style.
For example, to insert a comment into a text field that contains a single quote and punctuation, wrap the string in ` not ':
INSERT INTO cycling.comments (
id, created_at, comment
) VALUES (
e7ae5cf3-d358-4d99-b900-85902fda9bb0,
currentTimestamp(),
$$ It's pouring rain, race should have been postponed :'( $$
);
For more information, see Escaping characters.
Type |
Constants supported |
Description |
|
strings |
US-ASCII characters |
|
strings |
UTF-8 encoded string |
|
strings |
UTF-8 encoded string |
|
strings |
IP address string in IPv4 or IPv6 format |
date and time strings |
strings |
See Date and time types. |
Tuple type
The tuple type can store two or more values of the same or different data types in the same column.
They are similar to collections and user-defined types (UDTs), but tuples are less strict than collections, and they don’t require defining a custom type at the keyspace level.
However, DataStax recommends collections and UDTs over tuples due to the following limitations:
-
Tuples are always frozen, even if you don’t specify the
frozenkeyword. This means the entire field is overwritten when usingINSERTorUPDATE. Therefore, your statements must provide a value for each element in the tuple, and you must explicitly declarenullfor elements that have no value. -
You must access elements by position. This can make application development more difficult because you must remember the position at which each type is used and the meaning of each position.
-
During upgrades and migrations, additional steps are required to avoid data loss associated with the
tupletype.
If you choose to use tuples, limit their use to simple groupings. When the grouping becomes more complex, consider whether a collection would be more appropriate.
Tuples are fixed-length sets that can accommodate up to 32,768 fields, but a best practice is to use no more than five fields.
Additionally, tuples can contain nested tuples, and they can be nested in other data types.
For example, both of the following are valid: tuple<int,tuple<text,text>,boolean> and set<tuple<text,inet>>.
Table definition for tuples
In the table definition, use angle brackets and a comma delimiter to declare the tuple component types.
For example, create a table named cycling.nation_rank with a primary key of nation and a tuple to store the rank, cyclist name, and points total for a cyclist:
CREATE TABLE IF NOT EXISTS cycling.nation_rank (
nation text PRIMARY KEY,
info tuple<int, text, int>
);
You could also store the same data using rank as the primary key:
CREATE TABLE IF NOT EXISTS cycling.popular (
rank int PRIMARY KEY,
cinfo tuple<text, text, int>
);
Write tuples
When you insert or update rows, enclose tuple values in parentheses:
INSERT INTO cycling.nation_rank (
nation, info
) VALUES (
'Spain', (1, 'Alejandro VALVERDE', 9054)
);
INSERT INTO cycling.nation_rank (
nation, info
) VALUES (
'France', (2, 'Sylvain CHAVANEL', 6339)
);
INSERT INTO cycling.nation_rank (
nation, info
) VALUES (
'Belgium', (3, 'Phillippe GILBERT', 6222)
);
INSERT INTO cycling.nation_rank (
nation, info
) VALUES (
'Italy', (4, 'Davide REBELLINI', 6090)
);
Read indexed tuples
If a tuple column is indexed, SELECT statements can filter the indexed column in the WHERE clause:
SELECT * FROM cycling.nation_rank
WHERE info = (3, 'Phillippe GILBERT', 6222);
Nested tuples
Tuples can contain nested tuples.
This example stores geographic data in a nested tuple:
-
Create a table named
cycling.routeusing atupleto store each waypoint’s name and the location as latitude and longitude.The latitude and longitude tuple is nested inside the waypoint tuple.
CREATE TABLE IF NOT EXISTS cycling.route ( race_id int, race_name text, point_id int, lat_long tuple<text, tuple<float, float>>, PRIMARY KEY (race_id, point_id) ); -
Insert some data, enclosing both the inner and outer tuple values in parentheses:
INSERT INTO cycling.route ( race_id, race_name, point_id, lat_long ) VALUES ( 500, '47th Tour du Pays de Vaud', 1, ('Onnens', (46.8444, 6.6667)) ); INSERT INTO cycling.route ( race_id, race_name, point_id, lat_long ) VALUES ( 500, '47th Tour du Pays de Vaud', 2, ('Champagne', (46.833, 6.65)) ); INSERT INTO cycling.route ( race_id, race_name, point_id, lat_long ) VALUES ( 500, '47th Tour du Pays de Vaud', 3, ('Novalle', (46.833, 6.6)) ); INSERT INTO cycling.route ( race_id, race_name, point_id, lat_long ) VALUES ( 500, '47th Tour du Pays de Vaud', 4, ('Vuiteboeuf', (46.8, 6.55)) ); INSERT INTO cycling.route ( race_id, race_name, point_id, lat_long ) VALUES ( 500, '47th Tour du Pays de Vaud', 5, ('Baulmes', (46.7833, 6.5333)) ); INSERT INTO cycling.route ( race_id, race_name, point_id, lat_long ) VALUES ( 500, '47th Tour du Pays de Vaud', 6, ('Les Clées', (46.7222, 6.5222)) ); -
When queried, the entire tuple is returned as a single value for each row:
race_id | point_id | lat_long | race_name ---------+----------+----------------------------------+--------------------------- 500 | 1 | ('Onnens', (46.8444, 6.6667)) | 47th Tour du Pays de Vaud 500 | 2 | ('Champagne', (46.833, 6.65)) | 47th Tour du Pays de Vaud 500 | 3 | ('Novalle', (46.833, 6.6)) | 47th Tour du Pays de Vaud 500 | 4 | ('Vuiteboeuf', (46.8, 6.55)) | 47th Tour du Pays de Vaud 500 | 5 | ('Baulmes', (46.7833, 6.5333)) | 47th Tour du Pays de Vaud 500 | 6 | ('Les Clées', (46.7222, 6.5222)) | 47th Tour du Pays de Vaud (6 rows)
Unique identifier types
Use uuid and timeuuid types to represent unique identifiers.
They are often used to uniquely identify rows and ensure that each row has a distinct value.
| Type | Constants supported | Description |
|---|---|---|
|
uuids |
128-bit universally unique identifier (UUID)
Generate with the |
|
uuids |
128-bit Version 1 UUID; unique identifier that includes a conflict-free timestamp.
Generate with the |
User-defined type (UDT)
A user-defined type (UDT) is a custom type that can store multiple values in one column, similar to a map collection.
A UDT must be defined at the keyspace level before being used in a table definition.
Use UDTs judiciously to avoid performance issues and suboptimal data models.
For more information, see CREATE TYPE and Write a UDT.
Vector type
The vector type stores multiple values in a single column as an array of float32 values.
Vector arrays are limited to a maximum dimension of approximately 8,000 (213) items.
Deprecated types
The following types are supported for backward compatibility only:
-
custom type: Customized type added as a sub-class to
AbstractTypewhere the class name was fully qualified or relative to theorg.apache.cassandra.db.marshalpackage. Replaced by user defined type (UDT).