Home

Awesome

<a href="https://community-extensions.duckdb.org/extensions/chsql.html" target="_blank"> <img src="https://github.com/user-attachments/assets/9003897d-db6f-4a79-9443-9b72766b511b" width=200> </a>

DuckDB ClickHouse SQL extension

The DuckDB chsql community extension implements popular ClickHouse SQL syntax macros and functions,<br> making it easier for users to transition between the two database systems ⭐ designed for Quackpipe

<br>

Installation

chsql is distributed as a DuckDB Community Extension and can be installed using SQL:

INSTALL chsql FROM community;
LOAD chsql;

If you previously installed the chsql extension, upgrade using the FORCE command

FORCE INSTALL chsql FROM community;
LOAD chsql;

Usage Examples

Once installed, the macro functions provided by the extension can be used just like built-in functions.

Here's a random example out of 100s using the IPv4StringToNum and IPv4NumToString functions:

D INSTALL chsql FROM community;
D LOAD chsql;
D SELECT IPv4StringToNum('127.0.0.1'), IPv4NumToString(2130706433);
┌──────────────────────────────┬─────────────────────────────┐
│ ipv4stringtonum('127.0.0.1') │ ipv4numtostring(2130706433) │
│            int32             │           varchar           │
├──────────────────────────────┼─────────────────────────────┤
│                   2130706433 │ 127.0.0.1                   │
└──────────────────────────────┴─────────────────────────────┘

Remote Queries

The built-in ch_scan function can be used to query remote ClickHouse servers using the HTTP/s API

D SELECT * FROM ch_scan("SELECT number * 2 FROM numbers(10)", "https://play.clickhouse.com");

Supported Functions

👉 The list of supported aliases is available on the dedicated extension page<br> 👉 The combined list of supported functions can be obtained using an SQL Join

<br>

Motivation

Why is the DuckDB + chsql combo fun and useful

✔ DuckDB SQL is awesome and full of great functions.<br> ✔ ClickHouse SQL is awesome and full of great functions.

✔ The DuckDB library is ~51M and modular. Can LOAD extensions.<br> ❌ The ClickHouse monolith is ~551M and growing. No extensions.

✔ DuckDB is open source and protected by a no-profit foundation.<br> ❌ ClickHouse is open core and controlled by for-profit corporation.

✔ DuckDB embedded is fast, mature and elegantly integrated in many languages.<br> ❌ chdb is still experimental, unstable and currently only supports Python.

<img src="https://github.com/user-attachments/assets/a17efd68-d2e1-42a7-8ab9-1ea4c2ff11e3" width=700 /> <br> <br>

Functions

functionfun_typedescriptioncommentexample
IPv4NumToStringmacroCast IPv4 address from numeric to string formatSELECT IPv4NumToString(2130706433);
IPv4StringToNummacroCast IPv4 address from string to numeric formatSELECT IPv4StringToNum('127.0.0.1');
arrayExistsmacroCheck if any element of the array satisfies the conditionSELECT arrayExists(x -> x = 1, [1, 2, 3]);
arrayJoinmacroUnroll an array into multiple rowsSELECT arrayJoin([1, 2, 3]);
arrayMapmacroApplies a function to each element of an arraySELECT arrayMap(x -> x + 1, [1, 2, 3]);
bitCountmacroCounts the number of set bits in an integerSELECT bitCount(15);
ch_scantable_macroQuery a remote ClickHouse server using HTTP/s APIReturns the query resultsSELECT * FROM ch_scan('SELECT version()','https://play.clickhouse.com', format := 'parquet');
domainmacroExtracts the domain from a URLSELECT domain('https://clickhouse.com/docs');
emptymacroCheck if a string is emptySELECT empty('');
extractAllGroupsmacroExtracts all matching groups from a string using a regular expressionSELECT extractAllGroups('(\d+)', 'abc123');
formatDateTimemacroFormats a DateTime value into a stringSELECT formatDateTime(now(), '%Y-%m-%d');
generateUUIDv4macroGenerate a UUID v4 valueSELECT generateUUIDv4();
ifNullmacroReturns the first argument if not NULL, otherwise the secondSELECT ifNull(NULL, 'default');
intDivmacroPerforms integer divisionSELECT intDiv(10, 3);
intDivOZeromacroPerforms integer division but returns zero instead of throwing an error for division by zeroSELECT intDivOZero(10, 0);
intDivOrNullmacroPerforms integer division but returns NULL instead of throwing an error for division by zeroSELECT intDivOrNull(10, 0);
leftPadmacroPads a string on the left to a specified lengthSELECT leftPad('abc', 5, '*');
lengthUTF8macroReturns the length of a string in UTF-8 charactersSELECT lengthUTF8('Привет');
matchmacroPerforms a regular expression match on a stringSELECT match('abc123', '\d+');
minusmacroPerforms subtraction of two numbersSELECT minus(5, 3);
modulomacroCalculates the remainder of division (modulus)SELECT modulo(10, 3);
moduloOrZeromacroCalculates modulus but returns zero instead of error on division by zeroSELECT moduloOrZero(10, 0);
notEmptymacroCheck if a string is not emptySELECT notEmpty('abc');
numberstable_macroGenerates a sequence of numbers starting from 0Returns a table with a single column (UInt64)SELECT * FROM numbers(10);
parseURLmacroExtracts parts of a URLSELECT parseURL('https://clickhouse.com', 'host');
pathmacroExtracts the path from a URLSELECT path('https://clickhouse.com/docs');
plusmacroPerforms addition of two numbersSELECT plus(5, 3);
protocolmacroExtracts the protocol from a URLSELECT protocol('https://clickhouse.com');
read_parquet_mergetreefunctionMerge parquet files using a primary sorting key for fast range queriesexperimentalCOPY (SELECT * FROM read_parquet_mergetree(['/folder/*.parquet'], 'sortkey') TO 'sorted.parquet';
rightPadmacroPads a string on the right to a specified lengthSELECT rightPad('abc', 5, '*');
splitByCharmacroSplits a string by a given characterSELECT splitByChar(',', 'a,b,c');
toDayOfMonthmacroExtracts the day of the month from a dateSELECT toDayOfMonth('2023-09-10');
toFixedStringmacroConverts a value to a fixed-length stringSELECT toFixedString('abc', 5);
toFloatmacroConverts a value to a floatSELECT toFloat('123.45');
toFloatOrNullmacroConverts a value to float or returns NULL if the conversion failsSELECT toFloatOrNull('abc');
toFloatOrZeromacroConverts a value to float or returns zero if the conversion failsSELECT toFloatOrZero('abc');
toHourmacroExtracts the hour from a DateTime valueSELECT toHour(now());
toInt128macroConverts a value to a 128-bit integerSELECT toInt128('123456789012345678901234567890');
toInt128OrNullmacroConverts to a 128-bit integer or returns NULL on failureSELECT toInt128OrNull('abc');
toInt128OrZeromacroConverts to a 128-bit integer or returns zero on failureSELECT toInt128OrZero('abc');
toInt16macroConverts a value to a 16-bit integerSELECT toInt16('123');
toInt16OrNullmacroConverts to a 16-bit integer or returns NULL on failureSELECT toInt16OrNull('abc');
toInt16OrZeromacroConverts to a 16-bit integer or returns zero on failureSELECT toInt16OrZero('abc');
toInt256macroConverts a value to a 256-bit integerSELECT toInt256('12345678901234567890123456789012345678901234567890123456789012345678901234567890');
toInt256OrNullmacroConverts to a 256-bit integer or returns NULL on failureSELECT toInt256OrNull('abc');
toInt256OrZeromacroConverts to a 256-bit integer or returns zero on failureSELECT toInt256OrZero('abc');
toInt32macroConverts a value to a 32-bit integerSELECT toInt32('123');
toInt32OrNullmacroConverts to a 32-bit integer or returns NULL on failureSELECT toInt32OrNull('abc');
toInt32OrZeromacroConverts to a 32-bit integer or returns zero on failureSELECT toInt32OrZero('abc');
toInt64macroConverts a value to a 64-bit integerSELECT toInt64('123');
toInt64OrNullmacroConverts to a 64-bit integer or returns NULL on failureSELECT toInt64OrNull('abc');
toInt64OrZeromacroConverts to a 64-bit integer or returns zero on failureSELECT toInt64OrZero('abc');
toInt8macroConverts a value to an 8-bit integerSELECT toInt8('123');
toInt8OrNullmacroConverts to an 8-bit integer or returns NULL on failureSELECT toInt8OrNull('abc');
toInt8OrZeromacroConverts to an 8-bit integer or returns zero on failureSELECT toInt8OrZero('abc');
toMinutemacroExtracts the minute from a DateTime valueSELECT toMinute(now());
toMonthmacroExtracts the month from a Date valueSELECT toMonth('2023-09-10');
toSecondmacroExtracts the second from a DateTime valueSELECT toSecond(now());
toStringmacroConverts a value to a stringSELECT toString(123);
toUInt16macroConverts a value to an unsigned 16-bit integerSELECT toUInt16('123');
toUInt16OrNullmacroConverts to an unsigned 16-bit integer or returns NULL on failureSELECT toUInt16OrNull('abc');
toUInt16OrZeromacroConverts to an unsigned 16-bit integer or returns zero on failureSELECT toUInt16OrZero('abc');
toUInt32macroConverts a value to an unsigned 32-bit integerSELECT toUInt32('123');
toUInt32OrNullmacroConverts to an unsigned 32-bit integer or returns NULL on failureSELECT toUInt32OrNull('abc');
toUInt32OrZeromacroConverts to an unsigned 32-bit integer or returns zero on failureSELECT toUInt32OrZero('abc');
toUInt64macroConverts a value to an unsigned 64-bit integerSELECT toUInt64('123');
toUInt64OrNullmacroConverts to an unsigned 64-bit integer or returns NULL on failureSELECT toUInt64OrNull('abc');
toUInt64OrZeromacroConverts to an unsigned 64-bit integer or returns zero on failureSELECT toUInt64OrZero('abc');
toUInt8macroConverts a value to an unsigned 8-bit integerSELECT toUInt8('123');
toUInt8OrNullmacroConverts to an unsigned 8-bit integer or returns NULL on failureSELECT toUInt8OrNull('abc');
toUInt8OrZeromacroConverts to an unsigned 8-bit integer or returns zero on failureSELECT toUInt8OrZero('abc');
toYYYYMMmacroFormats a Date to 'YYYYMM' string formatSELECT toYYYYMM('2023-09-10');
toYYYYMMDDmacroFormats a Date to 'YYYYMMDD' string formatSELECT toYYYYMMDD('2023-09-10');
toYYYYMMDDhhmmssmacroFormats a DateTime to 'YYYYMMDDhhmmss' string formatSELECT toYYYYMMDDhhmmss(now());
toYearmacroExtracts the year from a Date or DateTime valueSELECT toYear('2023-09-10');
topLevelDomainmacroExtracts the top-level domain (TLD) from a URLSELECT topLevelDomain('https://example.com');
tupleConcatmacroConcatenates two tuples into one tupleSELECT tupleConcat((1, 'a'), (2, 'b'));
tupleDividemacroPerforms element-wise division between two tuplesSELECT tupleDivide((10, 20), (2, 5));
tupleDivideByNumbermacroDivides each element of a tuple by a numberSELECT tupleDivideByNumber((10, 20), 2);
tupleIntDivmacroPerforms element-wise integer division between two tuplesSELECT tupleIntDiv((10, 20), (3, 4));
tupleIntDivByNumbermacroPerforms integer division of each element of a tuple by a numberSELECT tupleIntDivByNumber((10, 20), 3);
tupleMinusmacroPerforms element-wise subtraction between two tuplesSELECT tupleMinus((10, 20), (5, 3));
tupleModulomacroPerforms element-wise modulus between two tuplesSELECT tupleModulo((10, 20), (3, 6));
tupleModuloByNumbermacroCalculates the modulus of each element of a tuple by a numberSELECT tupleModuloByNumber((10, 20), 3);
tupleMultiplymacroPerforms element-wise multiplication between two tuplesSELECT tupleMultiply((10, 20), (2, 5));
tupleMultiplyByNumbermacroMultiplies each element of a tuple by a numberSELECT tupleMultiplyByNumber((10, 20), 3);
tuplePlusmacroPerforms element-wise addition between two tuplesSELECT tuplePlus((1, 2), (3, 4));
urltable_macroPerforms queries against remote URLs using the specified formatSupports JSON, CSV, PARQUET, TEXT, BLOBSELECT * FROM url('https://urleng.com/test','JSON');
JSONExtractmacroExtracts JSON data based on key from a JSON objectSELECT JSONExtract(json_column, 'user.name');
JSONExtractStringmacroExtracts JSON data as a VARCHAR from a JSON objectSELECT JSONExtractString(json_column, 'user.email');
JSONExtractUIntmacroExtracts JSON data as an unsigned integer from a JSON objectSELECT JSONExtractUInt(json_column, 'user.age');
JSONExtractIntmacroExtracts JSON data as a 32-bit integer from a JSON objectSELECT JSONExtractInt(json_column, 'user.balance');
JSONExtractFloatmacroExtracts JSON data as a double from a JSON objectSELECT JSONExtractFloat(json_column, 'user.score');
JSONExtractRawmacroExtracts raw JSON data based on key from a JSON objectSELECT JSONExtractRaw(json_column, 'user.address');
JSONHasmacroChecks if a JSON key exists and is not nullSELECT JSONHas(json_column, 'user.active');
JSONLengthmacroReturns the length of a JSON arraySELECT JSONLength(json_column, 'items');
JSONTypemacroDetermines the type of JSON element at the given pathSELECT JSONType(json_column, 'user.data');
JSONExtractKeysmacroExtracts keys from a JSON objectSELECT JSONExtractKeys(json_column);
JSONExtractValuesmacroExtracts all values as text from a JSON objectSELECT JSONExtractValues(json_column);
equalsmacroChecks if two values are equalSELECT equals(column_a, column_b);
notEqualsmacroChecks if two values are not equalSELECT notEquals(column_a, column_b);
lessmacroChecks if one value is less than anotherSELECT less(column_a, column_b);
greatermacroChecks if one value is greater than anotherSELECT greater(column_a, column_b);
lessOrEqualsmacroChecks if one value is less than or equal to anotherSELECT lessOrEquals(column_a, column_b);
greaterOrEqualsmacroChecks if one value is greater than or equal to anotherSELECT greaterOrEquals(column_a, column_b);
dictGetmacroRetrieves an attribute from a VARIABLE string or MAPSELECT dictGet('dictionary_name', 'attribute');
Disclaimer

DuckDB ® is a trademark of DuckDB Foundation. ClickHouse® is a trademark of ClickHouse Inc. All trademarks, service marks, and logos mentioned or depicted are the property of their respective owners. The use of any third-party trademarks, brand names, product names, and company names is purely informative or intended as parody and does not imply endorsement, affiliation, or association with the respective owners.