Wednesday, 26 August 2026

Tuples in ClickHouse

  

A Tuple in ClickHouse is a data structure similar to an array, but unlike arrays (which are homogeneous), Tuples can store values of different types. This makes them useful for grouping logically related values of various types into a single column or expression.

 

Key Characteristics

·      Tuples can hold heterogeneous data types.

·      Elements can be accessed using tupleElement() or dot notation (if given names).

·      You can create tuples using the tuple() function.

 

Syntax

tuple(T1, T2, ..., Tn)

   

Each Ti can be of a different data type.

 

Example 1: Creation of tuple

 

SELECT tuple(1, 'a') AS x, toTypeName(x);

krishna :) SELECT tuple(1, 'a') AS x, toTypeName(x);

SELECT
    (1, 'a') AS x,
    toTypeName(x)

Query id: e3d19f03-5345-48ef-be73-e2dce002617f

Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 25.5.1.

   ┌─x───────┬─toTypeName(x)────────┐
1.  (1,'a')  Tuple(UInt8, String) 
   └─────────┴──────────────────────┘

1 row in set. Elapsed: 0.004 sec.

You can even create a tuple with single element.

 

SELECT tuple(42) AS single_tuple, toTypeName(single_tuple);

krishna :) SELECT tuple(42) AS single_tuple, toTypeName(single_tuple);

SELECT
    tuple(42) AS single_tuple,
    toTypeName(single_tuple)

Query id: 85324d4d-836c-406b-a078-1a797987e702

   ┌─single_tuple─┬─toTypeName(single_tuple)─┐
1.  (42)          Tuple(UInt8)             
   └──────────────┴──────────────────────────┘

1 row in set. Elapsed: 0.002 sec.

   

How to access tuple elements?

We can access tuple elements in two ways.

·      Using tupleElement method.

·      Using dot notation

 

Using tupleElement method

 

SELECT tupleElement(tuple(10, 'hello', now()), 2) AS second_element;

krishna :) SELECT tupleElement(tuple(10, 'hello', now()), 2) AS second_element;

SELECT (10, 'hello', now()).2 AS second_element

Query id: 0507a19c-990d-4912-a1e3-6dd8f3b930ab

   ┌─second_element─┐
1.  hello          
   └────────────────┘

1 row in set. Elapsed: 0.002 sec.

   

Using dot notation

 

WITH tuple(10, 'hello', now()) AS t
SELECT
    t.1 AS first,
    t.2 AS second,
    t.3 AS third;

krishna :) WITH tuple(10, 'hello', now()) AS t
SELECT
    t.1 AS first,
    t.2 AS second,
    t.3 AS third;

WITH (10, 'hello', now()) AS t
SELECT
    t.1 AS first,
    t.2 AS second,
    t.3 AS third

Query id: 2b7bde65-c744-4c8a-bc30-b7b626b974e0

   ┌─first─┬─second─┬───────────────third─┐
1.     10  hello   2025-05-17 18:03:51 
   └───────┴────────┴─────────────────────┘

1 row in set. Elapsed: 0.001 sec.

   

Realworld example

 

CREATE DATABASE IF NOT EXISTS demo_db;

CREATE TABLE demo_db.user_events (
    user_info Tuple(String, UInt8),  -- name, age
    event_date Date
) ENGINE = MergeTree()
ORDER BY event_date;

INSERT INTO demo_db.user_events VALUES
(('Ram', 30), '2024-08-01'),
(('Krishna', 25), '2024-08-02');

SELECT
    user_info.1 AS name,
    user_info.2 AS age,
    event_date
FROM demo_db.user_events;

   

In this example, I demonstrated how to use Tuples in ClickHouse to store heterogeneous data types within a single column. I created a user_events table where the user_info column is a tuple containing a user's name (String) and age (UInt8). After inserting sample data, we used dot notation to extract individual elements from the tuple in the SELECT query. This approach allows for compact and structured data modeling, especially when related values are logically grouped together.

 

krishna :) SELECT
    user_info.1 AS name,
    user_info.2 AS age,
    event_date
FROM demo_db.user_events;

SELECT
    user_info.1 AS name,
    user_info.2 AS age,
    event_date
FROM demo_db.user_events

Query id: 88444db0-8874-4a53-a72f-9fa08d388569

   ┌─name────┬─age─┬─event_date─┐
1.  Ram       30  2024-08-01 
2.  Krishna   25  2024-08-02 
   └─────────┴─────┴────────────┘

2 rows in set. Elapsed: 0.002 sec. 

   

How to detect data type of individual elements in tuple?

When you create tuples on the fly in ClickHouse (e.g., using the tuple() function in a SELECT statement), the system automatically infers the most appropriate data types for each element in the tuple. ClickHouse does this by determining the smallest compatible data type for each value:

 

·      Numeric values are assigned the smallest integer type that can represent them (e.g., 1 becomes UInt8).

·      String values are inferred as String.

·      If a NULL value is present, ClickHouse infers the type as Nullable(Nothing), indicating the type is unknown but nullable.

 

 

Example

 

SELECT tuple(1, 'Ram', 23, NULL) AS types, toTypeName(types)

krishna :) SELECT tuple(1, 'Ram', 23, NULL) AS types, toTypeName(types);

SELECT
    (1, 'Ram', 23, NULL) AS types,
    toTypeName(types)

Query id: 959db1d7-92b4-4ec5-bf6e-cc00c0f500e6

   ┌─types─────────────┬─toTypeName(types)──────────────────────────────┐
1.  (1,'Ram',23,NULL)  Tuple(UInt8, String, UInt8, Nullable(Nothing)) 
   └───────────────────┴────────────────────────────────────────────────┘

1 row in set. Elapsed: 0.001 sec.

   

Here:

·      1 is inferred as UInt8 (the smallest unsigned integer type).

·      'Ram' is inferred as String.

·      23 is inferred as UInt8

·      NULL has no explicit type, so ClickHouse assigns it Nullable(Nothing).


  

Previous                                                    Next                                                    Home

No comments:

Post a Comment