F.1. Functions #

By default, pgpro_axe functions are installed into the public schema. Currently, ALTER EXTENSION cannot move pgpro_axe to a different schema.

F.1.1. JSON Functions #

pgpro_axe supports all DuckDB JSON functions and aggregates. Postgres Pro JSON/JSONB functions are not supported.

F.1.2. MAP Functions #

cardinality(map_col duckdb.map) returns numeric #

Returns the size of a map (the number of key-value pairs).

Example F.1. 

-- Get the number of entries in a map
SELECT cardinality(r['map_col']) AS size
FROM duckdb.query(' SELECT MAP([''a'', ''b'', ''c''], [1, 2, 3]) AS map_col ') r;
-- Returns: 3

-- Empty map
SELECT cardinality(r['map_col']) AS size
FROM duckdb.query(' SELECT MAP([], []) AS map_col ') r;
-- Returns: 0

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map, the size of which to return

element_at(map_col duckdb.map, key duckdb.unresolved_type) returns duckdb.unresolved_type #

Returns the value for a given key as an array.

Example F.2. 

-- Get value for a specific key
SELECT element_at(r['map_col'], 'a') AS value
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: {1}

-- Non-existent key
SELECT element_at(r['map_col'], 'c') AS value
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: {}

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map from which to extract a value

key

duckdb.unresolved_type

The key for which to extract a value

map_concat(map_col duckdb.map, map_col2 duckdb.map) returns duckdb.map #

Merges two maps. On key collision, the value is taken from the last map.

Example F.3. 

-- Merge two maps
SELECT map_concat(r1['map1'], r2['map2']) AS merged
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map1 ') r1,
     duckdb.query(' SELECT MAP([''b'', ''c''], [3, 4]) AS map2 ') r2;
-- Returns: {a=1, b=3, c=4}

-- Note: 'b' value from map2 (3) overwrites map1's value (2)

Required parameters:

Name

Type

Description

map_col

duckdb.map

The first map to merge

map_col2

duckdb.map

The second map to merge

map_contains(map_col duckdb.map, key duckdb.unresolved_type) returns boolean #

Checks whether a map contains a given key.

Example F.4. 

-- Check if key exists
SELECT map_contains(r['map_col'], 'a') AS has_key
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: t (true)

-- Check for non-existent key
SELECT map_contains(r['map_col'], 'c') AS has_key
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: f (false)

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map where to check a key

key

duckdb.unresolved_type

The key to check

map_contains_entry(map_col duckdb.map, key duckdb.unresolved_type, value duckdb.unresolved_type) boolean #

Checks whether a map contains a given key-value pair.

Example F.5. 

-- Check if key-value pair exists
SELECT map_contains_entry(r['map_col'], 'a', 1) AS has_entry
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: t (true)

-- Check with wrong value for existing key
SELECT map_contains_entry(r['map_col'], 'a', 2) AS has_entry
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: f (false)

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map where to check a key-value pair

key

duckdb.unresolved_type

The key to check

value

duckdb.unresolved_type

The value to check

map_contains_value(map_col duckdb.map, value duckdb.unresolved_type) returns boolean #

Checks whether a map contains the specified value.

Example F.6. 

-- Check if value exists
SELECT map_contains_value(r['map_col'], 1) AS has_value
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: t (true)

-- Check for non-existent value
SELECT map_contains_value(r['map_col'], 3) AS has_value
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: f (false)

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map where to check a value

value

duckdb.unresolved_type

The value to check

map_entries(map_col duckdb.map) returns duckdb.struct[] #

Returns an array of structs (key, value) for each key-value pair in the map.

Example F.7. 

-- Get all key-value pairs as structs
SELECT map_entries(r['map_col']) AS entries
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: {"(a,1)","(b,2)"}

-- Access individual struct fields
SELECT unnest(map_entries(r['map_col'])) AS entry
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map from which to extract arrays of structs

map_extract(map_col duckdb.map, key duckdb.unresolved_type) returns duckdb.unresolved_type #

Extracts a value from a map using the specified key. If the key does not exist, returns an empty array.

Example F.8. 

-- Extract value from a map
SELECT map_extract(r['map_col'], 'a') AS value
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: {1}

-- Extract non-existent key
SELECT map_extract(r['map_col'], 'c') AS value
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: {}

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map from which to extract a value

key

duckdb.unresolved_type

The key to use for extracting a value

map_extract_value(map_col duckdb.map, key duckdb.unresolved_type) returns duckdb.unresolved_type #

Returns a value for the specified key or NULL if the key is not contained in the map.

Example F.9. 

-- Extract single value (not as array)
SELECT map_extract_value(r['map_col'], 'a') AS value
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: 1

-- Non-existent key returns NULL
SELECT map_extract_value(r['map_col'], 'c') AS value
FROM duckdb.query(' SELECT MAP([''a'', ''b''], [1, 2]) AS map_col ') r;
-- Returns: NULL

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map from which to extract a value

key

duckdb.unresolved_type

The key for which to extract a value

map_from_entries(entries duckdb.struct[]) returns duckdb.map #

Creates a map from an array of structs (k, v).

Example F.10. 

-- Create map from array of structs
SELECT map_from_entries(r['entries']) AS new_map
FROM duckdb.query('
    SELECT [{''k'': ''a'', ''v'': 1}, {''k'': ''b'', ''v'': 2}] AS entries
') r;
-- Returns: {a=1, b=2}

-- This is the inverse operation of map_entries
SELECT map_from_entries(map_entries(r['map_col'])) AS reconstructed
FROM duckdb.query(' SELECT MAP([''x'', ''y''], [10, 20]) AS map_col ') r;
-- Returns: {x=10, y=20}

Required parameters:

Name

Type

Description

entries

duckdb.struct[]

Array of structs with 'k' (key) and 'v' (value) fields

map_keys(map_col duckdb.map) returns duckdb.unresolved_type #

Returns all keys from a map as an array.

Example F.11. 

-- Get all keys from a map
SELECT map_keys(r['map_col']) AS keys
FROM duckdb.query(' SELECT MAP([''a'', ''b'', ''c''], [1, 2, 3]) AS map_col ') r;
-- Returns: {a,b,c}

-- Empty map
SELECT map_keys(r['map_col']) AS keys
FROM duckdb.query(' SELECT MAP([], []) AS map_col ') r;
-- Returns: {}

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map from which to extract keys

map_values(map_col duckdb.map) returns duckdb.unresolved_type #

Returns all values from a map as an array.

Example F.12. 

-- Get all values from a map
SELECT map_values(r['map_col']) AS values
FROM duckdb.query(' SELECT MAP([''a'', ''b'', ''c''], [1, 2, 3]) AS map_col ') r;
-- Returns: {1,2,3}

-- Empty map
SELECT map_values(r['map_col']) AS values
FROM duckdb.query(' SELECT MAP([], []) AS map_col ') r;
-- Returns: {}

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map from which to extract values

F.1.3. Aggregates Functions #

approx_count_distinct(expression) returns BIGINT #

Approximates the count of distinct elements using the HyperLogLog algorithm. This is much faster than COUNT(DISTINCT ...) for large datasets, with a small error rate.

Example F.13. 

-- Approximate distinct count of customer IDs
SELECT approx_count_distinct(customer_id) FROM orders;

-- Compare with exact count
SELECT
    approx_count_distinct(customer_id) AS approx_distinct,
    COUNT(DISTINCT customer_id) AS exact_distinct
FROM orders;

Required parameters:

Name

Type

Description

expression

any

The expression for which to count distinct values

F.1.4. Sampling Functions #

TABLESAMPLE (sampling_method(percentage | rows)) #

Samples a subset of rows from an analytical table or query result. This is useful for analyzing large datasets by working with representative samples, improving query performance for exploratory data analysis.

Example F.14. 

-- Sample 10% of rows from a table
SELECT * FROM large_table TABLESAMPLE SYSTEM(10);

-- Sample approximately 1000 rows
SELECT * FROM events TABLESAMPLE SYSTEM(1000 ROWS);

-- Sample from data lake files
SELECT * FROM read_parquet('s3://datalake/**/*.parquet') TABLESAMPLE SYSTEM(5);

-- Use sampling for quick data profiling
SELECT
    region,
    COUNT(*) AS sample_count,
    AVG(revenue) AS avg_revenue
FROM sales_data TABLESAMPLE SYSTEM(2)
GROUP BY region;

-- Sample from joins for performance
SELECT c.name, COUNT(o.id) AS order_count
FROM customers c
JOIN orders o TABLESAMPLE SYSTEM(10) ON c.id = o.customer_id
GROUP BY c.name;

Sampling methods:

  • SYSTEM: Random sampling at the storage level (faster, approximate percentage).

  • BERNOULLI: Row-by-row random sampling (slower, exact percentage).

Example F.15. 

-- System sampling (recommended for large tables)
SELECT * FROM huge_table TABLESAMPLE SYSTEM(1);

-- Bernoulli sampling (exact percentage)
SELECT * FROM medium_table TABLESAMPLE BERNOULLI(5);

Use cases:

  • Data exploration: Quick analysis of large datasets.

  • Performance testing: Test analytical queries on sample data.

  • Data profiling: Understand data distribution patterns.

  • ETL (Extract, Trasform, Load) operations development: Develop pipelines on sample data.

  • Quality checks: Validate data quality on samples.

Required parameters:

Name

Type

Description

sampling_method

keyword

SYSTEM or BERNOULLI

percentage

numeric

Percentage of rows to sample (0-100)

Optional parameters:

Name

Type

Description

rows

integer

Approximate number of rows to sample (use with ROWS keyword)

F.1.5. Time Functions #

time_bucket(bucket_width INTERVAL, timestamp_col TIMESTAMP, origin TIMESTAMP) returns TIMESTAMP #

Buckets timestamps into time intervals for time-series analysis. This function is compatible with the TimescaleDB time_bucket function, allowing for easier migration and interoperability.

Example F.16. 

-- Group events by hour
SELECT time_bucket(INTERVAL '1 hour', created_at) AS hour_bucket, COUNT(*)
FROM events
GROUP BY hour_bucket
ORDER BY hour_bucket;

-- Group by 15-minute intervals
SELECT time_bucket(INTERVAL '15 minutes', timestamp_col), AVG(value)
FROM sensor_data
WHERE timestamp_col >= '2024-01-01'
GROUP BY 1
ORDER BY 1;

Required parameters:

Name

Type

Description

bucket_width

interval

The time interval for bucketing (e.g., '1 hour', '15 minutes')

timestamp_col

timestamp

The timestamp column to bucket

Optional parameters:

Name

Type

Description

origin

timestamp

The origin point for bucketing. Buckets are aligned to this timestamp

strftime (timestamp_expr, format_string) returns TEXT #

Formats timestamps as strings using standard format codes. This function provides flexible timestamp formatting for display and export purposes.

Example F.17. 

-- Format current timestamp
SELECT strftime(NOW(), '%Y-%m-%d %H:%M:%S') AS formatted_time;

-- Format timestamps in different formats
SELECT
    order_id,
    strftime(created_at, '%Y-%m-%d') AS order_date,
    strftime(created_at, '%H:%M') AS order_time,
    strftime(created_at, '%A, %B %d, %Y') AS readable_date
FROM orders;

-- Use for partitioning file exports
COPY (SELECT * FROM events WHERE event_date = '2024-01-01')
TO 's3://bucket/events/' || strftime('2024-01-01'::timestamp, '%Y/%m/%d') || '/events.parquet';

Common format codes:

  • %Y: 4-digit year (2024).

  • %m: Month as number (01-12).

  • %d: Day of month (01-31).

  • %H: Hour (00-23).

  • %M: Minute (00-59).

  • %S: Second (00-59).

  • %A: Full weekday name (Monday).

  • %B: Full month name (January).

Optional parameters:

Name

Type

Description

timestamp_expr

timestamp

The timestamp value to format

format_string

text

The format string with format codes

strptime(string_expr, format_string) returns TIMESTAMP #

Parses strings into timestamps using format codes.

Example F.18. 

-- Parse date strings
SELECT strptime('2024-01-15 14:30:00', '%Y-%m-%d %H:%M:%S') AS parsed_timestamp;

-- Parse different formats
SELECT
    strptime('Jan 15, 2024', '%b %d, %Y') AS date1,
    strptime('15/01/2024', '%d/%m/%Y') AS date2,
    strptime('2024-01-15T14:30:00Z', '%Y-%m-%dT%H:%M:%SZ') AS iso_date;

-- Parse log timestamps
SELECT
    log_id,
    strptime(timestamp_string, '%Y-%m-%d %H:%M:%S') AS parsed_time,
    message
FROM raw_logs;

Required parameters:

Name

Type

Description

string_expr

text

The string to parse as a timestamp

format_string

text

The format string describing the input format

epoch(timestamp_expr) returns BIGINT #

Converts timestamps to Unix epoch seconds (seconds since 1970-01-01 00:00:00 UTC).

Example F.19. 

-- Get current epoch time
SELECT epoch(NOW()) AS current_epoch;

-- Convert timestamps for API usage
SELECT
    event_id,
    epoch(event_timestamp) AS epoch_seconds
FROM events;

-- Filter using epoch time
SELECT * FROM events
WHERE epoch(created_at) > 1640995200; -- After 2022-01-01

Required parameters:

Name

Type

Description

map_col

duckdb.map

The map from which to extract parameters

key

duckdb.unresolved_type

The key to find in the map

epoch_ms(timestamp_expr) returns BIGINT #

Converts timestamps to Unix epoch milliseconds.

Example F.20. 

-- High-precision timestamp for JavaScript
SELECT epoch_ms(NOW()) AS timestamp_ms;

-- For time-series data
SELECT
    sensor_id,
    epoch_ms(reading_time) AS timestamp_ms,
    value
FROM sensor_readings;

Required parameters:

Name

Type

Description

timestamp_expr

timestamp

The timestamp to convert to Unix epoch milliseconds

epoch_ms(milliseconds) returns TIMESTAMP #

Converts Unix epoch milliseconds to a timestamp.

Example F.21. 

-- Convert epoch milliseconds to timestamp
SELECT epoch_ms(1640995200000) AS timestamp_from_ms; -- 2022-01-01 00:00:00

-- Convert stored milliseconds back to timestamps
SELECT
    event_id,
    epoch_ms(timestamp_ms) AS event_time
FROM events;

Required parameters:

Name

Type

Description

milliseconds

bigint

Milliseconds since the Unix epoch

epoch_us(timestamp_expr) returns BIGINT #

Converts timestamps to Unix epoch microseconds.

Example F.22. 

-- Microsecond precision timestamps
SELECT epoch_us(NOW()) AS timestamp_us;

Required parameters:

Name

Type

Description

timestamp_expr

timestamp

The timestamp to convert to Unix epoch microseconds

epoch_ns(timestamp_expr) returns BIGINT #

Converts timestamps to Unix epoch nanoseconds.

Example F.23. 

-- Nanosecond precision timestamps
SELECT epoch_ns(NOW()) AS timestamp_ns;

Required parameters:

Name

Type

Description

timestamp_expr

timestamp

The timestamp to convert to Unix epoch nanoseconds

make_timestamp(microseconds) returns TIMESTAMP #

Creates a timestamp from microseconds since the Unix epoch (1970-01-01 00:00:00 UTC).

Example F.24. 

-- Create timestamp from current epoch microseconds
SELECT make_timestamp(epoch_us(NOW())) AS reconstructed_timestamp;

-- Create specific timestamps
SELECT make_timestamp(1640995200000000) AS new_years_2022; -- 2022-01-01 00:00:00

Required parameters:

Name

Type

Description

microseconds

BIGINT

Microseconds since the Unix epoch

make_timestamptz(microseconds) returns TIMESTAMPTZ #

Creates a timestamp with timezone from microseconds since the Unix epoch.

Example F.25. 

-- Create timestamptz from current epoch microseconds
SELECT make_timestamptz(epoch_us(NOW())) AS reconstructed_timestamptz;

-- Create specific timestamptz
SELECT make_timestamptz(1640995200000000) AS new_years_2022_tz;

Required parameters:

Name

Type

Description

microseconds

bigint

Microseconds since the Unix epoch

F.1.6. DuckDB Administration Functions #

duckdb.install_extension(extension_name TEXT, repository TEXT DEFAULT 'core') returns bool #

Installs a DuckDB extension and configures it to be loaded automatically in every session that uses pgpro_axe.

Example F.26. 

  SELECT duckdb.install_extension('iceberg');
  SELECT duckdb.install_extension('avro', 'community');

Since this function can be used to download and install any extensions, it can only be executed by a superuser by default. You can allow execution by other administrators, such as my_admin, by granting them the following privileges:

Example F.27. 

  GRANT ALL ON FUNCTION duckdb.install_extension(TEXT, TEXT) TO my_admin;

Required parameters:

Name

Type

Description

extension_name

text

The name of the extension to install

duckdb.load_extension(extension_name TEXT) returns void #

Loads a DuckDB extension for the current session only. Unlike duckdb.install_extension, this does not configure the extension to be loaded automatically in future sessions.

Example F.28. 

SELECT duckdb.load_extension('iceberg');

Required parameters:

Name

Type

Description

extension_name

text

The name of the extension to load

duckdb.autoload_extension(extension_name TEXT, autoload BOOLEAN) returns void #

Specifies whether an installed extension must be automatically loaded in new sessions.

Example F.29. 

-- Disable auto-loading for an extension
SELECT duckdb.autoload_extension('iceberg', false);

-- Enable auto-loading for an extension
SELECT duckdb.autoload_extension('iceberg', true);

Required parameters:

Name

Type

Description

extension_nametext

The name of the extension

autoload

boolean

Specifies whether the extension must be automatically loaded in new sessions

duckdb.query(query TEXT) returns SETOF duckdb.row #

Executes the given SELECT command directly against DuckDB. This can be useful if the DuckDB syntax makes the query easier to write or to use a function that is not exposed by pgpro_axe yet.

Example F.30. 

This command puts the FROM clause before the SELECT command and uses a list comprehension. Both of these features are not supported in Postgres Pro.

  SELECT * FROM duckdb.query('FROM range(10) AS a(a) SELECT [a for i in generate_series(0, a)] as arr');

duckdb.raw_query(extension_name TEXT) returns void #

Runs an arbitrary command directly against DuckDB.

Compared to duckdb.query, this function can execute any command, not just SELECT. The main downside is that it does not return its result as rows but instead sends the command result to logs. It is recommended to use duckdb.query when possible.