> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-fix-nav-issues.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Documentación de referencia completa de pg_clickhouse

# Documentación de referencia de pg_clickhouse

<div id="description">
  ## Descripción
</div>

pg\_clickhouse es una extensión de PostgreSQL que permite ejecutar consultas de forma remota
en bases de datos de ClickHouse e incluye un [foreign data wrapper]. Es compatible con
PostgreSQL 13 y versiones posteriores, y con ClickHouse 23 y versiones posteriores.

<div id="getting-started">
  ## Primeros pasos
</div>

La forma más sencilla de probar pg\_clickhouse es la [imagen de Docker], que contiene
la imagen de Docker estándar de PostgreSQL con las extensiones pg\_clickhouse y \[re2]\[re2
extension]:

```sh theme={null}
docker run --name pg_clickhouse -e POSTGRES_PASSWORD=my_pass \
       -d ghcr.io/clickhouse/pg_clickhouse:18
docker exec -it pg_clickhouse psql -U postgres
```

Consulta el [tutorial](/es/integrations/connectors/tools/pg_clickhouse/tutorial) para empezar a importar tablas de ClickHouse y
delegar la ejecución de consultas.

<div id="usage">
  ## Uso
</div>

```sql theme={null}
CREATE EXTENSION pg_clickhouse;
CREATE SERVER taxi_srv FOREIGN DATA WRAPPER clickhouse_fdw
       OPTIONS(driver 'binary', host 'localhost', dbname 'taxi');
CREATE USER MAPPING FOR CURRENT_USER SERVER taxi_srv
       OPTIONS (user 'default');
CREATE SCHEMA taxi;
IMPORT FOREIGN SCHEMA taxi FROM SERVER taxi_srv INTO taxi;
```

<div id="versioning-policy">
  ## Política de versionado
</div>

pg\_clickhouse sigue el \[versionado semántico] para sus versiones públicas.

* La versión mayor se incrementa por cambios en la API
* La versión menor se incrementa por cambios de SQL compatibles con versiones anteriores
* La versión de parche se incrementa por cambios únicamente en el binario

Una vez instalado, PostgreSQL realiza un seguimiento de dos variantes de la versión:

* La versión de la biblioteca (definida por `PG_MODULE_MAGIC` en PostgreSQL 18 y
  posteriores) incluye la versión semántica completa, visible en la salida de la
  función `pgch_version()` o de la función de Postgres [`pg_get_loaded_modules()`].
* La versión de la extensión (definida en el archivo de control) incluye solo las versiones mayor
  y menor, visibles en la tabla `pg_catalog.pg_extension`, en la
  salida de la función `pg_available_extension_versions()` y en `\dx
  pg_clickhouse`.

En la práctica, esto significa que una versión que incrementa la versión de parche, por ejemplo,
de `v0.1.0` a `v0.1.1`, beneficia a todas las bases de datos que han cargado `v0.1` y
no necesitan ejecutar `ALTER EXTENSION` para beneficiarse de la actualización.

Por otro lado, una versión que incrementa la versión menor o mayor
irá acompañada de scripts de actualización de SQL, y todas las bases de datos existentes que contengan
la extensión deben ejecutar `ALTER EXTENSION pg_clickhouse UPDATE` para beneficiarse de
la actualización.

<div id="ddl-sql-reference">
  ## Referencia de SQL DDL
</div>

Las siguientes expresiones SQL [DDL] usan pg\_clickhouse.

<div id="create-extension">
  ### CREATE EXTENSION
</div>

Utiliza [CREATE EXTENSION] para añadir pg\_clickhouse a una base de datos:

```sql theme={null}
CREATE EXTENSION pg_clickhouse;
```

Utiliza `WITH SCHEMA` para instalarlo en un esquema específico (recomendado):

```sql theme={null}
CREATE SCHEMA ch;
CREATE EXTENSION pg_clickhouse WITH SCHEMA ch;
```

<div id="alter-extension">
  ### ALTER EXTENSION
</div>

Utilice [ALTER EXTENSION] para modificar pg\_clickhouse. Ejemplos:

* Después de instalar una nueva versión de pg\_clickhouse, use la cláusula `UPDATE`:

  ```sql theme={null}
  ALTER EXTENSION pg_clickhouse UPDATE;
  ```

* Use `SET SCHEMA` para mover la extensión a un nuevo esquema:

  ```sql theme={null}
  CREATE SCHEMA ch;
  ALTER EXTENSION pg_clickhouse SET SCHEMA ch;
  ```

<div id="drop-extension">
  ### DROP EXTENSION
</div>

Utiliza [DROP EXTENSION] para eliminar pg\_clickhouse de una base de datos:

```sql theme={null}
DROP EXTENSION pg_clickhouse;
```

Este comando falla si hay algún objeto que dependa de pg\_clickhouse. Use
la cláusula `CASCADE` para eliminarlos también:

```sql theme={null}
DROP EXTENSION pg_clickhouse CASCADE;
```

<div id="create-server">
  ### CREATE SERVER
</div>

Use [CREATE SERVER] para crear un servidor foráneo que se conecte a un servidor de ClickHouse. Ejemplo:

```sql theme={null}
CREATE SERVER taxi_srv FOREIGN DATA WRAPPER clickhouse_fdw
       OPTIONS(driver 'binary', host 'localhost', dbname 'taxi');
```

Las opciones admitidas son:

* `driver`: El controlador de conexión de ClickHouse que se usará, ya sea "binary" o
  "http". **Obligatorio.**
* `dbname`: La base de datos de ClickHouse que se usará al conectarse. El valor predeterminado es
  "default".
* `fetch_size`: Tamaño aproximado del lote en bytes para HTTP streaming. Los lotes
  se dividen en los límites de las filas. El valor predeterminado es `50000000` (50 MB). `0` desactiva
  el streaming y almacena en búfer la respuesta completa. Las tablas foráneas pueden sobrescribir este
  valor.
* `host`: El nombre de host del servidor de ClickHouse. El valor predeterminado es "localhost";
* `port`: El puerto del servidor de ClickHouse al que conectarse. Los valores predeterminados son los
  siguientes:
  * 9440 si `driver` es "binary" y `host` es un host de ClickHouse Cloud
  * 9004 si `driver` es "binary" y `host` no es un host de ClickHouse Cloud
  * 8443 si `driver` es "http" y `host` es un host de ClickHouse Cloud
  * 8123 si `driver` es "http" y `host` no es un host de ClickHouse Cloud

<div id="alter-server">
  ### ALTER SERVER
</div>

Utilice [ALTER SERVER] para modificar un servidor foráneo. Ejemplo:

```sql theme={null}
ALTER SERVER taxi_srv OPTIONS (SET driver 'http');
```

Las opciones son las mismas que en [CREATE SERVER](#create-server).

<div id="drop-server">
  ### DROP SERVER
</div>

Use [DROP SERVER] para eliminar un servidor foráneo:

```sql theme={null}
DROP SERVER taxi_srv;
```

Este comando falla si algún otro objeto depende del servidor. Use `CASCADE` para
eliminar también esas dependencias:

```sql theme={null}
DROP SERVER taxi_srv CASCADE;
```

<div id="create-user-mapping">
  ### CREATE USER MAPPING
</div>

Use [CREATE USER MAPPING] para asignar un usuario de PostgreSQL a un usuario de ClickHouse. Por
ejemplo, para asignar el usuario actual de PostgreSQL al usuario remoto de ClickHouse al
conectarse al servidor foráneo `taxi_srv`:

```sql theme={null}
CREATE USER MAPPING FOR CURRENT_USER SERVER taxi_srv
       OPTIONS (user 'demo');
```

Las opciones admitidas son:

* `user`: El nombre del usuario de ClickHouse. El valor predeterminado es "default".
* `password`: La contraseña del usuario de ClickHouse.

<div id="alter-user-mapping">
  ### ALTER USER MAPPING
</div>

Use [ALTER USER MAPPING] para cambiar la definición de una asignación de usuario:

```sql theme={null}
ALTER USER MAPPING FOR CURRENT_USER SERVER taxi_srv
       OPTIONS (SET user 'default');
```

Las opciones son las mismas que las de [CREATE USER MAPPING](#create-user-mapping).

<div id="drop-user-mapping">
  ### DROP USER MAPPING
</div>

Utilice [DROP USER MAPPING] para eliminar una asignación de usuario:

```sql theme={null}
DROP USER MAPPING FOR CURRENT_USER SERVER taxi_srv;
```

<div id="import-foreign-schema">
  ### IMPORT FOREIGN SCHEMA
</div>

Use [IMPORT FOREIGN SCHEMA] para importar todas las tablas definidas en una base de datos de ClickHouse
como tablas foráneas en un esquema de PostgreSQL:

```sql theme={null}
CREATE SCHEMA taxi;
IMPORT FOREIGN SCHEMA demo FROM SERVER taxi_srv INTO taxi;
```

Usa `LIMIT TO` para limitar la importación a tablas concretas:

```sql theme={null}
IMPORT FOREIGN SCHEMA demo LIMIT TO (trips) FROM SERVER taxi_srv INTO taxi;
```

Usa `EXCEPT` para excluir tablas:

```sql theme={null}
IMPORT FOREIGN SCHEMA demo EXCEPT (users) FROM SERVER taxi_srv INTO taxi;
```

pg\_clickhouse obtendrá una lista de todas las tablas de la base de datos
de ClickHouse especificada ("demo" en los ejemplos anteriores), recuperará las
definiciones de las columnas de cada una y ejecutará comandos [CREATE FOREIGN
TABLE](#create-foreign-table) para crear las tablas externas. Las columnas se
definirán mediante los [tipos de datos
compatibles](#data-types) y, cuando sea posible detectarlas, las opciones
compatibles con [CREATE FOREIGN TABLE](#create-foreign-table).

<Tip>
  **Conservación del uso de mayúsculas y minúsculas en los identificadores importados**

  `IMPORT FOREIGN SCHEMA` ejecuta `quote_identifier()` sobre los nombres de las
  tablas y columnas que importa, lo que pone entre comillas dobles los
  identificadores que contienen caracteres en mayúsculas o espacios en blanco.
  Por lo tanto, esos nombres de tablas y columnas deben ir entre comillas
  dobles en las consultas de PostgreSQL. Los nombres compuestos únicamente por
  minúsculas y sin espacios en blanco no necesitan comillas.

  Por ejemplo, dada esta tabla de ClickHouse:

  ```sql theme={null}
  CREATE OR REPLACE TABLE test
  (
      id UInt64,
      Name TEXT,
      updatedAt DateTime DEFAULT now()
  )
  ENGINE = MergeTree
  ORDER BY id;
  ```

  `IMPORT FOREIGN SCHEMA` crea esta tabla externa:

  ```sql theme={null}
  CREATE TABLE test
  (
      id          BIGINT      NOT NULL,
      "Name"      TEXT        NOT NULL,
      "updatedAt" TIMESTAMPTZ NOT NULL
  );
  ```

  Por lo tanto, las consultas deben entrecomillar los identificadores de forma
  adecuada; por ejemplo:

  ```sql theme={null}
  SELECT id, "Name", "updatedAt" FROM test;
  ```

  Para crear objetos con nombres distintos o completamente en minúsculas (y,
  por tanto, que no distingan entre mayúsculas y minúsculas), use [CREATE FOREIGN TABLE](#create-foreign-table).
</Tip>

<div id="create-foreign-table">
  ### CREATE FOREIGN TABLE
</div>

Use [CREATE FOREIGN TABLE] para crear una tabla foránea que permite consultar datos de
una base de datos de ClickHouse:

```sql theme={null}
CREATE FOREIGN TABLE acts (
    user_id    bigint NOT NULL,
    page_views int,
    duration   smallint,
    sign       smallint
) SERVER taxi_srv OPTIONS(
    table_name 'acts'
    engine 'CollapsingMergeTree'
);
```

Las opciones de tabla compatibles son:

* `database`: El nombre de la base de datos remota. De forma predeterminada, usa la base de datos
  definida para el servidor foráneo.
* `fetch_size`: Tamaño aproximado del lote en bytes para HTTP streaming. Anula
  el `fetch_size` a nivel de servidor. El valor predeterminado es `50000000` (50 MB). `0` desactiva el
  streaming y almacena en el búfer la respuesta completa.
* `table_name`: El nombre de la tabla remota. De forma predeterminada, usa el nombre especificado
  para la tabla foránea.
* `engine`: El [motor de tabla] usado por la tabla de ClickHouse. Para
  `CollapsingMergeTree()` y `AggregatingMergeTree()`, pg\_clickhouse
  aplica automáticamente los parámetros a las expresiones de función ejecutadas en
  la tabla.

Use el [tipo de dato](#data-types) adecuado para el tipo de dato remoto de ClickHouse
de cada columna. Las opciones de columna compatibles son:

* `column_name`: El nombre de la columna en ClickHouse, que se usa con
  preferencia sobre el nombre del atributo de PostgreSQL al reconstruir consultas e
  inserciones. Es útil para asignar nombres de columna de PostgreSQL en minúsculas y sin comillas a
  columnas de ClickHouse sensibles a mayúsculas y minúsculas; por ejemplo:

  ```sql theme={null}
  CREATE FOREIGN TABLE hits (
      watchid    bigint   OPTIONS(column_name 'WatchID'),
      javaenable smallint OPTIONS(column_name 'JavaEnable'),
      title      text     OPTIONS(column_name 'Title')
  ) SERVER taxi_srv OPTIONS(table_name 'hits');
  ```

* `AggregateFunction`: El nombre de la función de agregación aplicada a una
  columna de \[AggregateFunction Type]. Asigne el tipo de dato al tipo de ClickHouse
  pasado a la función y especifique el nombre de la función de agregación mediante
  la opción de columna correspondiente; pg\_clickhouse añadirá automáticamente
  `Merge` a la función de agregación que evalúe la columna.

  ```sql theme={null}
  CREATE FOREIGN TABLE test (
      column1 bigint  OPTIONS(AggregateFunction 'uniq'),
      column2 integer OPTIONS(AggregateFunction 'anyIf'),
      column3 bigint  OPTIONS(AggregateFunction 'quantiles(0.5, 0.9)')
  ) SERVER clickhouse_srv;
  ```

* `SimpleAggregateFunction`: El nombre de la función de agregación aplicada a
  una columna de \[SimpleAggregateFunction Type]. Asigne el tipo de dato al
  tipo de ClickHouse pasado a la función y especifique el nombre de la
  función de agregación mediante la opción de columna correspondiente.

<div id="alter-foreign-table">
  ### ALTER FOREIGN TABLE
</div>

Utilice [ALTER FOREIGN TABLE] para cambiar la definición de una tabla foránea:

```sql theme={null}
ALTER TABLE table ALTER COLUMN b OPTIONS (SET AggregateFunction 'count');
```

Las opciones de tabla y columna admitidas son las mismas que para [CREATE FOREIGN
TABLE].

<div id="drop-foreign-table">
  ### DROP FOREIGN TABLE
</div>

Utilice [DROP FOREIGN TABLE] para eliminar una tabla foránea:

```sql theme={null}
DROP FOREIGN TABLE acts;
```

Este comando produce un error si hay algún objeto que dependa de la tabla foránea.
Use la cláusula `CASCADE` para eliminarlos también:

```sql theme={null}
DROP FOREIGN TABLE acts CASCADE;
```

<div id="dml-sql-reference">
  ## Referencia de SQL DML
</div>

Las expresiones SQL [DML] que se muestran a continuación pueden usar pg\_clickhouse. Los ejemplos dependen de
estas tablas de ClickHouse:

```sql theme={null}
CREATE TABLE logs (
    req_id    Int64 NOT NULL,
    start_at   DateTime64(6, 'UTC') NOT NULL,
    duration  Int32 NOT NULL,
    resource  Text  NOT NULL,
    method    Enum8('GET' = 1, 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH', 'QUERY') NOT NULL,
    node_id   Int64 NOT NULL,
    response  Int32 NOT NULL
) ENGINE = MergeTree
  ORDER BY start_at;

CREATE TABLE nodes (
    node_id Int64 NOT NULL,
    name    Text  NOT NULL,
    region  Text  NOT NULL,
    arch    Text  NOT NULL,
    os      Text  NOT NULL
) ENGINE = MergeTree
  PRIMARY KEY node_id;
```

<div id="explain">
  ### EXPLAIN
</div>

El comando [EXPLAIN] funciona como es de esperar, pero la opción `VERBOSE` provoca que se emita la consulta "Remote SQL" de ClickHouse:

```pgsql theme={null}
try=# EXPLAIN (VERBOSE)
       SELECT resource, avg(duration) AS average_duration
         FROM logs
        GROUP BY resource;
                                     QUERY PLAN
------------------------------------------------------------------------------------
 Foreign Scan  (cost=1.00..5.10 rows=1000 width=64)
   Output: resource, (avg(duration))
   Relations: Aggregate on (logs)
   Remote SQL: SELECT resource, avg(duration) FROM "default".logs GROUP BY resource
(4 rows)
```

Esta consulta se envía a ClickHouse a través de un nodo de plan "Foreign Scan", el
SQL remoto.

<div id="select">
  ### SELECT
</div>

Use la instrucción [SELECT] para ejecutar consultas en las tablas de pg\_clickhouse igual
que en cualquier otra tabla:

```pgsql theme={null}
try=# SELECT start_at, duration, resource FROM logs WHERE req_id = 4117909262;
          start_at          | duration |    resource
----------------------------+----------+----------------
 2025-12-05 15:07:32.944188 |      175 | /widgets/totem
(1 row)
```

pg\_clickhouse procura trasladar la ejecución de la consulta a ClickHouse tanto como
sea posible, incluidas las funciones de agregado. Use [EXPLAIN](#explain) para determinar
hasta qué punto se aplica el pushdown. Para la consulta anterior, por ejemplo, toda la ejecución se traslada
a ClickHouse

```pgsql theme={null}
try=# EXPLAIN (VERBOSE, COSTS OFF)
       SELECT start_at, duration, resource FROM logs WHERE req_id = 4117909262;
                                             QUERY PLAN
-----------------------------------------------------------------------------------------------------
 Foreign Scan on public.logs
   Output: start_at, duration, resource
   Remote SQL: SELECT start_at, duration, resource FROM "default".logs WHERE ((req_id = 4117909262))
(3 rows)
```

pg\_clickhouse también aplica pushdown a JOINs entre tablas que provienen del mismo servidor remoto:

```pgsql theme={null}
try=# EXPLAIN (ANALYZE, VERBOSE)
       SELECT name, count(*), round(avg(duration))
         FROM logs
         LEFT JOIN nodes on logs.node_id = nodes.node_id
        GROUP BY name;
                                                                                  QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Foreign Scan  (cost=1.00..5.10 rows=1000 width=72) (actual time=3.201..3.221 rows=8.00 loops=1)
   Output: nodes.name, (count(*)), (round(avg(logs.duration), 0))
   Relations: Aggregate on ((logs) LEFT JOIN (nodes))
   Remote SQL: SELECT r2.name, count(*), round(avg(r1.duration), 0) FROM  "default".logs r1 ALL LEFT JOIN "default".nodes r2 ON (((r1.node_id = r2.node_id))) GROUP BY r2.name
   FDW Time: 0.086 ms
 Planning Time: 0.335 ms
 Execution Time: 3.261 ms
(7 rows)
```

Hacer JOIN con una tabla local generará consultas menos eficientes sin
una configuración cuidadosa. En este ejemplo, hacemos una copia local de la
tabla `nodes` y hacemos JOIN con ella en lugar de con la tabla remota:

```pgsql theme={null}
try=# CREATE TABLE local_nodes AS SELECT * FROM nodes;
SELECT 8

try=# EXPLAIN (ANALYZE, VERBOSE)
       SELECT name, count(*), round(avg(duration))
         FROM logs
         LEFT JOIN local_nodes on logs.node_id = local_nodes.node_id
        GROUP BY name;
                                                             QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=147.65..150.65 rows=200 width=72) (actual time=6.215..6.235 rows=8.00 loops=1)
   Output: local_nodes.name, count(*), round(avg(logs.duration), 0)
   Group Key: local_nodes.name
   Batches: 1  Memory Usage: 32kB
   Buffers: shared hit=1
   ->  Hash Left Join  (cost=31.02..129.28 rows=2450 width=36) (actual time=2.202..5.125 rows=1000.00 loops=1)
         Output: local_nodes.name, logs.duration
         Hash Cond: (logs.node_id = local_nodes.node_id)
         Buffers: shared hit=1
         ->  Foreign Scan on public.logs  (cost=10.00..20.00 rows=1000 width=12) (actual time=2.089..3.779 rows=1000.00 loops=1)
               Output: logs.req_id, logs.start_at, logs.duration, logs.resource, logs.method, logs.node_id, logs.response
               Remote SQL: SELECT duration, node_id FROM "default".logs
               FDW Time: 1.447 ms
         ->  Hash  (cost=14.90..14.90 rows=490 width=40) (actual time=0.090..0.091 rows=8.00 loops=1)
               Output: local_nodes.name, local_nodes.node_id
               Buckets: 1024  Batches: 1  Memory Usage: 9kB
               Buffers: shared hit=1
               ->  Seq Scan on public.local_nodes  (cost=0.00..14.90 rows=490 width=40) (actual time=0.069..0.073 rows=8.00 loops=1)
                     Output: local_nodes.name, local_nodes.node_id
                     Buffers: shared hit=1
 Planning:
   Buffers: shared hit=14
 Planning Time: 0.551 ms
 Execution Time: 6.589 ms
```

En este caso, podemos trasladar una mayor parte de la agregación a ClickHouse
agrupando por `node_id` en lugar de por la columna local, y luego unirnos
a la tabla de búsqueda más adelante:

```sql theme={null}
try=# EXPLAIN (ANALYZE, VERBOSE)
       WITH remote AS (
           SELECT node_id, count(*), round(avg(duration))
             FROM logs
            GROUP BY node_id
       )
       SELECT name, remote.count, remote.round
         FROM remote
         JOIN local_nodes
           ON remote.node_id = local_nodes.node_id
        ORDER BY name;
                                                          QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=65.68..66.91 rows=490 width=72) (actual time=4.480..4.484 rows=8.00 loops=1)
   Output: local_nodes.name, remote.count, remote.round
   Sort Key: local_nodes.name
   Sort Method: quicksort  Memory: 25kB
   Buffers: shared hit=4
   ->  Hash Join  (cost=27.60..43.79 rows=490 width=72) (actual time=4.406..4.422 rows=8.00 loops=1)
         Output: local_nodes.name, remote.count, remote.round
         Inner Unique: true
         Hash Cond: (local_nodes.node_id = remote.node_id)
         Buffers: shared hit=1
         ->  Seq Scan on public.local_nodes  (cost=0.00..14.90 rows=490 width=40) (actual time=0.010..0.016 rows=8.00 loops=1)
               Output: local_nodes.node_id, local_nodes.name, local_nodes.region, local_nodes.arch, local_nodes.os
               Buffers: shared hit=1
         ->  Hash  (cost=15.10..15.10 rows=1000 width=48) (actual time=4.379..4.381 rows=8.00 loops=1)
               Output: remote.count, remote.round, remote.node_id
               Buckets: 1024  Batches: 1  Memory Usage: 9kB
               ->  Subquery Scan on remote  (cost=1.00..15.10 rows=1000 width=48) (actual time=4.337..4.360 rows=8.00 loops=1)
                     Output: remote.count, remote.round, remote.node_id
                     ->  Foreign Scan  (cost=1.00..5.10 rows=1000 width=48) (actual time=4.330..4.349 rows=8.00 loops=1)
                           Output: logs.node_id, (count(*)), (round(avg(logs.duration), 0))
                           Relations: Aggregate on (logs)
                           Remote SQL: SELECT node_id, count(*), round(avg(duration), 0) FROM "default".logs GROUP BY node_id
                           FDW Time: 0.055 ms
 Planning:
   Buffers: shared hit=5
 Planning Time: 0.319 ms
 Execution Time: 4.562 ms
```

El nodo "Foreign Scan" ahora aplica la agregación por `node_id` en origen, lo que reduce
el número de filas que deben traerse de vuelta a Postgres de 1000 (todas
ellas) a solo 8, una por cada nodo.

<div id="prepare-execute-deallocate">
  ### PREPARE, EXECUTE, DEALLOCATE
</div>

A partir de la versión v0.1.2, pg\_clickhouse admite consultas parametrizadas, creadas principalmente
mediante el comando [PREPARE]:

```pgsql theme={null}
try=# PREPARE avg_durations_between_dates(date, date) AS
       SELECT date(start_at), round(avg(duration)) AS average_duration
         FROM logs
        WHERE date(start_at) BETWEEN $1 AND $2
        GROUP BY date(start_at)
        ORDER BY date(start_at);
PREPARE
```

Use [EXECUTE] como de costumbre para ejecutar una sentencia preparada:

```pgsql theme={null}
try=# EXECUTE avg_durations_between_dates('2025-12-09', '2025-12-13');
    date    | average_duration
------------+------------------
 2025-12-09 |              190
 2025-12-10 |              194
 2025-12-11 |              197
 2025-12-12 |              190
 2025-12-13 |              195
(5 rows)
```

<Warning>
  La ejecución parametrizada impide que el [http driver](#create-server)
  convierta correctamente las zonas horarias de DateTime en versiones de ClickHouse anteriores a la 25.8,
  donde se \[corrigió] el [error subyacente]. Ten en cuenta que, a veces, PostgreSQL usa
  un plan de consulta parametrizado incluso sin usar `PREPARE`. Para las consultas que
  requieran una conversión precisa de la zona horaria, si actualizar a la 25.8 o una versión
  posterior no es una opción, utiliza en su lugar el [binary driver](#create-server).
</Warning>

pg\_clickhouse delega las agregaciones, como es habitual, como se ve en la
salida detallada de [EXPLAIN](#explain):

```pgsql theme={null}
try=# EXPLAIN (VERBOSE) EXECUTE avg_durations_between_dates('2025-12-09', '2025-12-13');
                                                                                                            QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Foreign Scan  (cost=1.00..5.10 rows=1000 width=36)
   Output: (date(start_at)), (round(avg(duration), 0))
   Relations: Aggregate on (logs)
   Remote SQL: SELECT date(start_at), round(avg(duration), 0) FROM "default".logs WHERE ((date(start_at) >= '2025-12-09')) AND ((date(start_at) <= '2025-12-13')) GROUP BY (date(start_at)) ORDER BY date(start_at) ASC NULLS LAST
(4 rows)
```

Tenga en cuenta que ha enviado los valores de fecha completos, no los marcadores de posición de los parámetros.
Esto se cumple en las primeras cinco solicitudes, como se describe en las
[notas sobre PREPARE] de PostgreSQL. En la sexta ejecución, envía los
[parámetros de consulta] de ClickHouse con el formato `{param:type}`:
parámetros:

```pgsql theme={null}
                                                                                                         QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Foreign Scan  (cost=1.00..5.10 rows=1000 width=36)
   Output: (date(start_at)), (round(avg(duration), 0))
   Relations: Aggregate on (logs)
   Remote SQL: SELECT date(start_at), round(avg(duration), 0) FROM "default".logs WHERE ((date(start_at) >= {p1:Date})) AND ((date(start_at) <= {p2:Date})) GROUP BY (date(start_at)) ORDER BY date(start_at) ASC NULLS LAST
(4 rows)
```

Use [DEALLOCATE] para liberar una sentencia preparada:

```pgsql theme={null}
try=# DEALLOCATE avg_durations_between_dates;
DEALLOCATE
```

<div id="insert">
  ### INSERT
</div>

Utilice el comando [INSERT] para insertar valores en una tabla remota de ClickHouse:

```pgsql theme={null}
try=# INSERT INTO nodes(node_id, name, region, arch, os)
VALUES (9,  'Augustin Gamarra', 'us-west-2', 'amd64', 'Linux')
     , (10, 'Cerisier', 'us-east-2', 'amd64', 'Linux')
     , (11, 'Dewalt', 'use-central-1', 'arm64', 'macOS')
;
INSERT 0 3
```

<div id="copy">
  ### COPY
</div>

Usa el comando [COPY] para insertar un lote de filas en una tabla remota de ClickHouse:

```pgsql theme={null}
try=# COPY logs FROM stdin CSV;
4285871863,2025-12-05 11:13:58.360760,206,/widgets,POST,8,401
4020882978,2025-12-05 11:33:48.248450,199,/users/1321945,HEAD,3,200
3231273177,2025-12-05 12:20:42.158575,220,/search,GET,2,201
\.
>> COPY 3
```

> **⚠️ Limitaciones de la API de inserción por lotes**
>
> pg\_clickhouse aún no ha implementado compatibilidad con la API de inserción por lotes
> del FDW de PostgreSQL. Por lo tanto, [COPY] actualmente usa sentencias [INSERT](#insert) para
> insertar registros. Esto se mejorará en una versión futura.

<div id="load">
  ### LOAD
</div>

Utilice [LOAD] para cargar la biblioteca compartida pg\_clickhouse:

```pgsql theme={null}
try=# LOAD 'pg_clickhouse';
LOAD
```

No suele ser necesario usar [LOAD], ya que Postgres cargará automáticamente
pg\_clickhouse la primera vez que se utilice alguna de sus
funcionalidades (funciones, tablas foráneas, etc.).

La única ocasión en la que puede resultar útil [LOAD] pg\_clickhouse es para [SET](#set)
los parámetros de pg\_clickhouse antes de ejecutar consultas que dependan de ellos.

<div id="set">
  ### SET
</div>

Use [SET] para definir los parámetros de configuración personalizados de pg\_clickhouse.

<div id="pg_clickhousesession_settings">
  #### `pg_clickhouse.session_settings`
</div>

El parámetro `pg_clickhouse.session_settings` permite establecer la [configuración de
ClickHouse] que se aplicará a las consultas posteriores. Ejemplo:

```sql theme={null}
SET pg_clickhouse.session_settings = 'join_use_nulls 1, final 1';
```

El valor predeterminado es `join_use_nulls 1, group_by_use_nulls 1, final 1`. Establézcalo en una
cadena vacía para volver a usar la configuración del servidor de ClickHouse.

```sql theme={null}
SET pg_clickhouse.session_settings = '';
```

La sintaxis es una lista de pares clave/valor delimitados por comas y separados por uno o
más espacios. Las claves deben corresponder a la [configuración de ClickHouse]. Use una barra invertida para escapar los espacios,
las comas y las barras invertidas en los valores:

```sql theme={null}
SET pg_clickhouse.session_settings = 'join_algorithm grace_hash\,hash';
```

O bien use valores entre comillas simples para evitar escapar los espacios y las comas; considere
usar \[dollar quoting] para evitar tener que usar comillas dobles:

```sql theme={null}
SET pg_clickhouse.session_settings = $$join_algorithm 'grace_hash,hash'$$;
```

Si te importa la legibilidad y necesitas establecer muchos parámetros, usa varias
líneas, por ejemplo:

```sql theme={null}
SET pg_clickhouse.session_settings TO $$
    connect_timeout 2,
    count_distinct_implementation uniq,
    final 1,
    group_by_use_nulls 1,
    join_algorithm 'prefer_partial_merge',
    join_use_nulls 1,
    log_queries_min_type QUERY_FINISH,
    max_block_size 32768,
    max_execution_time 45,
    max_result_rows 1024,
    metrics_perf_events_list 'this,that',
    network_compression_method ZSTD,
    poll_interval 5,
    totals_mode after_having_auto
$$;
```

Algunos ajustes se ignorarán en los casos en que interfieran con el
funcionamiento de pg\_clickhouse. Entre ellos se incluyen:

* `date_time_output_format`: el driver HTTP requiere que sea "iso"
* `format_tsv_null_representation`: el driver HTTP requiere el valor predeterminado
* `output_format_tsv_crlf_end_of_line` el driver HTTP requiere el valor predeterminado

Por lo demás, pg\_clickhouse no valida estos ajustes, sino que los pasa a
ClickHouse en cada consulta. Por tanto, admite todos los ajustes de cada
versión de ClickHouse.

Ten en cuenta que pg\_clickhouse debe cargarse antes de configurar
`pg_clickhouse.session_settings`; usa [precarga de bibliotecas compartidas] o
simplemente uno de los objetos de la extensión para asegurarte de que se cargue.

<div id="pg_clickhousepushdown_regex">
  #### `pg_clickhouse.pushdown_regex`
</div>

El parámetro `pg_clickhouse.pushdown_regex` controla si pg\_clickhouse
transfiere las funciones y los operadores de expresiones regulares. Lo hace de forma predeterminada;
establezca este parámetro en false para evitarlo:

```sql theme={null}
SET pg_clickhouse.pushdown_regex = 'false';
```

Consulta [Expresiones regulares](#regular-expressions) para obtener más detalles.

<div id="alter-role">
  ### ALTER ROLE
</div>

Use el comando `SET` de [ALTER ROLE] para [precargar](#preloading) pg\_clickhouse
y/o [SET](#set) sus parámetros para roles específicos:

```pgsql theme={null}
try=# ALTER ROLE CURRENT_USER SET session_preload_libraries = pg_clickhouse;
ALTER ROLE

try=# ALTER ROLE CURRENT_USER SET pg_clickhouse.session_settings = 'final 1';
ALTER ROLE
```

Utilice el comando `RESET` de [ALTER ROLE] para restablecer la precarga de pg\_clickhouse
y/o los parámetros:

```pgsql theme={null}
try=# ALTER ROLE CURRENT_USER RESET session_preload_libraries;
ALTER ROLE

try=# ALTER ROLE CURRENT_USER RESET pg_clickhouse.session_settings;
ALTER ROLE
```

<div id="preloading">
  ## Precarga
</div>

Si todas o casi todas las conexiones a Postgres necesitan usar pg\_clickhouse,
considere usar la [precarga de bibliotecas compartidas] para cargarlo automáticamente:

<div id="session_preload_libraries">
  ### `session_preload_libraries`
</div>

Carga la biblioteca compartida en cada nueva conexión a PostgreSQL:

```ini theme={null}
session_preload_libraries = pg_clickhouse
```

Útil para aplicar las actualizaciones sin reiniciar el servidor: basta con
volver a conectarse. También puede establecerse para usuarios o roles específicos mediante [ALTER
ROLE](#alter-role).

<div id="shared_preload_libraries">
  ### `shared_preload_libraries`
</div>

Carga la biblioteca compartida en el proceso padre de PostgreSQL al iniciarse:

```ini theme={null}
shared_preload_libraries = pg_clickhouse
```

Útil para ahorrar memoria y reducir la sobrecarga en cada sesión, pero requiere que se
reinicie el clúster cuando se actualiza la biblioteca.

<div id="data-types">
  ## Tipos de datos
</div>

pg\_clickhouse asigna los siguientes tipos de datos de ClickHouse a tipos de datos
de PostgreSQL. [IMPORT FOREIGN SCHEMA](#import-foreign-schema) usa el primer tipo
indicado en la columna de PostgreSQL al importar columnas; se pueden usar tipos
adicionales en las sentencias [CREATE FOREIGN TABLE](#create-foreign-table):

| ClickHouse | PostgreSQL       | Notas                                    |
| ---------- | ---------------- | ---------------------------------------- |
| Bool       | boolean          |                                          |
| Date       | date             |                                          |
| Date32     | date             |                                          |
| DateTime   | timestamptz      |                                          |
| Decimal    | numeric          |                                          |
| Float32    | real             |                                          |
| Float64    | double precision |                                          |
| IPv4       | inet             |                                          |
| IPv6       | inet             |                                          |
| Int16      | smallint         |                                          |
| Int32      | integer          |                                          |
| Int64      | bigint           |                                          |
| Int8       | smallint         |                                          |
| JSON       | jsonb, json      |                                          |
| String     | text, bytea      |                                          |
| UInt16     | integer          |                                          |
| UInt32     | bigint           |                                          |
| UInt64     | bigint           | Produce errores con valores > BIGINT max |
| UInt8      | smallint         |                                          |
| UUID       | uuid             |                                          |

A continuación se ofrecen notas y detalles adicionales.

<div id="bytea">
  ### BYTEA
</div>

ClickHouse no ofrece un equivalente al tipo [BYTEA] de PostgreSQL, pero
permite almacenar cualquier secuencia de bytes en el tipo [String]. En general, las cadenas de ClickHouse
deben mapearse al tipo [TEXT] de PostgreSQL; sin embargo, cuando se trabaja con datos binarios, mapéelas
a [BYTEA]. Ejemplo:

```sql theme={null}
-- Crear tabla de ClickHouse con columnas String.
SELECT clickhouse_raw_query($$
    CREATE TABLE bytes (
        c1 Int8, c2 String, c3 String
    ) ENGINE = MergeTree ORDER BY (c1);
$$);

-- Crear tabla externa con columnas BYTEA.
CREATE FOREIGN TABLE bytes (
    c1 int,
    c2 BYTEA,
    c3 BYTEA
) SERVER ch_srv OPTIONS( table_name 'bytes' );

-- Insertar datos binarios en la tabla externa.
INSERT INTO bytes
SELECT n, sha224(bytea('val'||n)), decode(md5('int'||n), 'hex')
  FROM generate_series(1, 4) n;

-- Ver los resultados.
SELECT * FROM bytes;
```

Esa consulta `SELECT` final producirá como salida:

```pgsql theme={null}
c1 |                             c2                             |                 c3
----+------------------------------------------------------------+------------------------------------
  1 | \x1bf7f0cc821d31178616a55a8e0c52677735397cdde6f4153a9fd3d7 | \xae3b28cde02542f81acce8783245430d
  2 | \x5f6e9e12cd8592712e638016f4b1a2e73230ee40db498c0f0b1dc841 | \x23e7c6cacb8383f878ad093b0027d72b
  3 | \x53ac2c1fa83c8f64603fe9568d883331007d6281de330a4b5e728f9e | \x7e969132fc656148b97b6a2ee8bc83c1
  4 | \x4e3c2e4cb7542a45173a8dac939ddc4bc75202e342ebc769b0f5da2f | \x8ef30f44c65480d12b650ab6b2b04245
(4 rows)
```

Tenga en cuenta que si hay bytes nulos en las columnas de ClickHouse, una tabla
externa que use columnas [TEXT] no mostrará los valores correctos:

```sql theme={null}
-- Crear tabla externa con columnas TEXT.
CREATE FOREIGN TABLE texts (
    c1 int,
    c2 TEXT,
    c3 TEXT
) SERVER ch_srv OPTIONS( table_name 'bytes' );

-- Codificar datos binarios en hexadecimal.
SELECT c1, encode(c2::bytea, 'hex'), encode(c3::bytea, 'hex') FROM texts ORDER BY c1;
```

Producirá la siguiente salida:

```pgsql theme={null}
c1 |                          encode                          |              encode
----+----------------------------------------------------------+----------------------------------
  1 | 1bf7f0cc821d31178616a55a8e0c52677735397cdde6f4153a9fd3d7 | ae3b28cde02542f81acce8783245430d
  2 | 5f6e9e12cd8592712e638016f4b1a2e73230ee40db498c0f0b1dc841 | 23e7c6cacb8383f878ad093b
  3 | 53ac2c1fa83c8f64603fe9568d883331                         | 7e969132fc656148b97b6a2ee8bc83c1
  4 | 4e3c2e4cb7542a45173a8dac939ddc4bc75202e342ebc769b0f5da2f | 8ef30f44c65480d12b650ab6b2b04245
(4 rows)
```

Tenga en cuenta que las filas dos y tres contienen valores truncados. Esto se debe a que
PostgreSQL utiliza cadenas terminadas en nul y no admite nuls en sus
cadenas.

Intentar insertar valores binarios en columnas [TEXT] funcionará correctamente
y dará el resultado esperado:

```sql theme={null}
-- Insertar mediante columnas de texto:
TRUNCATE texts;
INSERT INTO texts
SELECT n, sha224(bytea('val'||n)), decode(md5('int'||n), 'hex')
  FROM generate_series(1, 4) n;

-- Ver los datos.
SELECT c1, encode(c2::bytea, 'hex'), encode(c3::bytea, 'hex') FROM texts ORDER BY c1;
```

Las columnas de texto serán correctas:

```pgsql theme={null}

 c1 |                          encode                          |              encode
----+----------------------------------------------------------+----------------------------------
  1 | 1bf7f0cc821d31178616a55a8e0c52677735397cdde6f4153a9fd3d7 | ae3b28cde02542f81acce8783245430d
  2 | 5f6e9e12cd8592712e638016f4b1a2e73230ee40db498c0f0b1dc841 | 23e7c6cacb8383f878ad093b0027d72b
  3 | 53ac2c1fa83c8f64603fe9568d883331007d6281de330a4b5e728f9e | 7e969132fc656148b97b6a2ee8bc83c1
  4 | 4e3c2e4cb7542a45173a8dac939ddc4bc75202e342ebc769b0f5da2f | 8ef30f44c65480d12b650ab6b2b04245
(4 filas)
```

Pero leerlos como [BYTEA] no funcionará:

```pgsql theme={null}
# SELECT * FROM bytes;
 c1 |                                                           c2                                                           |                                   c3
----+------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------
  1 | \x5c783162663766306363383231643331313738363136613535613865306335323637373733353339376364646536663431353361396664336437 | \x5c786165336232386364653032353432663831616363653837383332343534333064
  2 | \x5c783566366539653132636438353932373132653633383031366634623161326537333233306565343064623439386330663062316463383431 | \x5c783233653763366361636238333833663837386164303933623030323764373262
  3 | \x5c783533616332633166613833633866363436303366653935363864383833333331303037643632383164653333306134623565373238663965 | \x5c783765393639313332666336353631343862393762366132656538626338336331
  4 | \x5c783465336332653463623735343261343531373361386461633933396464633462633735323032653334326562633736396230663564613266 | \x5c783865663330663434633635343830643132623635306162366232623034323435
(4 filas)
```

<Tip>
  Por regla general, usa las columnas [TEXT] solo para cadenas codificadas y las columnas [BYTEA]
  solo para datos binarios, y no alternes nunca entre ellas.
</Tip>

<div id="function-and-operator-reference">
  ## Referencia de funciones y operadores
</div>

<div id="functions">
  ### Funciones
</div>

Estas funciones sirven de interfaz para consultar una base de datos de ClickHouse.

<div id="clickhouse_raw_query">
  #### `clickhouse_raw_query`
</div>

```sql theme={null}
SELECT clickhouse_raw_query(
    'CREATE TABLE t1 (x String) ENGINE = Memory',
    'host=localhost port=8123'
);
```

Conéctese a un servicio de ClickHouse a través de su interfaz HTTP, ejecute una sola
consulta y desconéctese. El segundo argumento opcional especifica una cadena de
conexión cuyo valor predeterminado es `host=localhost port=8123`. Los parámetros de conexión
admitidos son:

* `host`: El host al que conectarse; obligatorio.
* `port`: El puerto HTTP al que conectarse; el valor predeterminado es `8123`, a menos que `host` sea un
  host de ClickHouse Cloud, en cuyo caso el valor predeterminado es `8443`
* `dbname`: El nombre de la base de datos a la que conectarse.
* `username`: El nombre de usuario con el que conectarse; el valor predeterminado es `default`
* `password`: La contraseña que se usará para autenticarse; de forma predeterminada no hay contraseña

De forma predeterminada, ningún rol tiene acceso `EXECUTE` a esta función; considere [GRANT]ar
acceso solo a los roles que realmente necesiten ejecutar consultas ad hoc de ClickHouse,
por ejemplo, un rol de administrador de ClickHouse dedicado:

Útil para consultas que no devuelven registros, pero las consultas que sí devuelven valores
se devolverán como un único valor de texto:

```sql theme={null}
SELECT clickhouse_raw_query(
    'SELECT schema_name, schema_owner from information_schema.schemata',
    'host=localhost port=8123'
);
```

```sql theme={null}
      clickhouse_raw_query
---------------------------------
 INFORMATION_SCHEMA      default+
 default default                +
 git     default                +
 information_schema      default+
 system  default                +

(1 row)
```

<div id="pushdown-functions">
  ### Funciones con pushdown
</div>

`pg_clickhouse` aplica pushdown a un subconjunto de las funciones integradas de PostgreSQL usadas
en expresiones condicionales (cláusulas `HAVING` y `WHERE`). Ese subconjunto se corresponde con los equivalentes de ClickHouse
de la siguiente manera:

* `abs`: [abs](/es/reference/functions/regular-functions/arithmetic-functions#abs)
* `factorial`: [factorial](/es/reference/functions/regular-functions/math-functions#factorial)
* `mod` (int2/int4/int8/numeric): [módulo](/es/reference/functions/regular-functions/arithmetic-functions#modulo)
* `pow` & `power` (float8/numeric): [pow](/es/reference/functions/regular-functions/math-functions#pow)
* `round`: [round](/es/reference/functions/regular-functions/rounding-functions#round)
* `sin`, `cos`, `tan`, `atan`, `atan2`, `sinh`, `cosh`, `tanh`, `asinh`, `degrees`, `radians`, `pi`: [funciones matemáticas de ClickHouse](/es/reference/functions/regular-functions/math-functions)
  con el mismo nombre. `asin`, `acos`, `atanh`, `acosh` no se ejecutan mediante pushdown: PG
  genera un error con valores fuera de rango, mientras que CH devuelve `NaN`.
* `date_part`:
  * `date_part('day')`: [toDayOfMonth](/es/reference/functions/regular-functions/date-time-functions#toDayOfMonth)
  * `date_part('doy')`: [toDayOfYear](/es/reference/functions/regular-functions/date-time-functions#toDayOfYear)
  * `date_part('dow')`: [toDayOfWeek](/es/reference/functions/regular-functions/date-time-functions#toDayOfWeek)
  * `date_part('year')`: [toYear](/es/reference/functions/regular-functions/date-time-functions#toYear)
  * `date_part('month')`: [toMonth](/es/reference/functions/regular-functions/date-time-functions#toMonth)
  * `date_part('hour')`: [toHour](/es/reference/functions/regular-functions/date-time-functions#toHour)
  * `date_part('minute')`: [toMinute](/es/reference/functions/regular-functions/date-time-functions#toMinute)
  * `date_part('second')`: [toSecond](/es/reference/functions/regular-functions/date-time-functions#toSecond)
  * `date_part('quarter')`: [toQuarter](/es/reference/functions/regular-functions/date-time-functions#toQuarter)
  * `date_part('isoyear')`: [toISOYear](/es/reference/functions/regular-functions/date-time-functions#toISOYear)
  * `date_part('week')`: [toISOYear](/es/reference/functions/regular-functions/date-time-functions#toISOWeek)
  * `date_part('epoch')`: [toISOYear](/es/reference/functions/regular-functions/date-time-functions#toUnixTimestamp)
* `date_trunc`:
  * `date_trunc('week')`: [toMonday](/es/reference/functions/regular-functions/date-time-functions#toMonday)
  * `date_trunc('second')`: [toStartOfSecond](/es/reference/functions/regular-functions/date-time-functions#toStartOfSecond)
  * `date_trunc('minute')`: [toStartOfMinute](/es/reference/functions/regular-functions/date-time-functions#toStartOfMinute)
  * `date_trunc('hour')`: [toStartOfHour](/es/reference/functions/regular-functions/date-time-functions#toStartOfHour)
  * `date_trunc('day')`: [toStartOfDay](/es/reference/functions/regular-functions/date-time-functions#toStartOfDay)
  * `date_trunc('month')`: [toStartOfMonth](/es/reference/functions/regular-functions/date-time-functions#toStartOfMonth)
  * `date_trunc('quarter')`: [toStartOfQuarter](/es/reference/functions/regular-functions/date-time-functions#toStartOfQuarter)
  * `date_trunc('year')`: [toStartOfYear](/es/reference/functions/regular-functions/date-time-functions#toStartOfYear)
* `extract(field FROM source)`: las mismas correspondencias que `date_part`
* `date(timestamp)` & `date(timestamptz)`: [toDate](/es/reference/functions/regular-functions/type-conversion-functions#toDate)
  (representado como alias de CH `date`)
* `array_position`: [indexOf](/es/reference/functions/regular-functions/array-functions#indexOf)
* `array_cat`: [arrayConcat](/es/reference/functions/regular-functions/array-functions#arrayConcat)
* `array_append`: [arrayPushBack](/es/reference/functions/regular-functions/array-functions#arrayPushBack)
* `array_prepend`: [arrayPushFront](/es/reference/functions/regular-functions/array-functions#arrayPushFront)
* `array_remove`: [arrayRemove](/es/reference/functions/regular-functions/array-functions#arrayRemove)
* `array_length` & `cardinality`: [length](/es/reference/functions/regular-functions/array-functions#length)
* `array_to_string`: [arrayStringConcat](/es/reference/functions/regular-functions/array-functions#arrayStringConcat)
* `string_to_array`: [splitByString](/es/reference/functions/regular-functions/splitting-merging-functions#splitByString)
* `split_part`: [splitByString](/es/reference/functions/regular-functions/splitting-merging-functions#splitByString) + índice de array
* `trim_array`: [arrayResize](/es/reference/functions/regular-functions/array-functions#arrayResize)
* `array_fill`: [arrayWithConstant](/es/reference/functions/regular-functions/array-functions#arrayWithConstant)
* `array_reverse`: [arrayReverse](/es/reference/functions/regular-functions/array-functions#arrayReverse)
* `array_shuffle`: [arrayShuffle](/es/reference/functions/regular-functions/array-functions#arrayShuffle)
* `array_sample`: [arrayRandomSample](/es/reference/functions/regular-functions/array-functions#arrayRandomSample)
* `array_sort`: [arraySort](/es/reference/functions/regular-functions/array-functions#arraySort) / [arrayReverseSort](/es/reference/functions/regular-functions/array-functions#arrayReverseSort)
* `btrim`: [trimBoth](/es/reference/functions/regular-functions/string-functions#trimboth)
* `ltrim`: [ltrim](/es/reference/functions/regular-functions/string-functions#ltrim)
* `rtrim`: [rtrim](/es/reference/functions/regular-functions/string-functions#rtrim)
* `concat_ws`: [concatWithSeparator](/es/reference/functions/regular-functions/string-functions#concatwithseparator)
* `lower(text)`: [lowerUTF8](/es/reference/functions/regular-functions/string-functions#lowerutf8)
* `upper(text)`: [upperUTF8](/es/reference/functions/regular-functions/string-functions#upperutf8)
* `substring(text, ...)` & `substr(text, ...)`: [substringUTF8](/es/reference/functions/regular-functions/string-functions#substringutf8)
* `substring(bytea, ...)` & `substr(bytea, ...)`: [substring](/es/reference/functions/regular-functions/string-functions#substring)
* `length(text)`: [lengthUTF8](/es/reference/functions/regular-functions/string-functions#lengthutf8)
* `length(bytea)` & `octet_length`: [length](/es/reference/functions/regular-functions/array-functions#length)
* `reverse(text)`: [reverseUTF8](/es/reference/functions/regular-functions/string-functions#reverseutf8)
* `reverse(bytea)`: [reverse](/es/reference/functions/regular-functions/string-functions#reverse)
* `strpos`: [positionUTF8](/es/reference/functions/regular-functions/string-search-functions#positionutf8)
* `regexp_like`: [match](/es/reference/functions/regular-functions/string-search-functions#match)
* `regexp_replace`: [replaceRegexpOne](/es/reference/functions/regular-functions/string-replace-functions#replaceRegexpOne) o [replaceRegexpOne](/es/reference/functions/regular-functions/string-replace-functions#replaceRegexpAll) si está presente la bandera `g`
* `regexp_split_to_array`: [splitByRegexp](/es/reference/functions/regular-functions/splitting-merging-functions#splitByRegexp)
* `md5`: [MD5](/es/reference/functions/regular-functions/hash-functions#MD5)
* `json_extract_path_text`: [sintaxis de subcolumnas](/es/reference/data-types/newjson#reading-json-paths-as-sub-columns)
* `json_extract_path`: [toJSONString](/es/reference/functions/regular-functions/json-functions#toJSONString) + [sintaxis de subcolumnas](/es/reference/data-types/newjson#reading-json-paths-as-sub-columns)
* `jsonb_extract_path_text`: [sintaxis de subcolumnas](/es/reference/data-types/newjson#reading-json-paths-as-sub-columns)
* `jsonb_extract_path`: [toJSONString](/es/reference/functions/regular-functions/json-functions#toJSONString) + [sintaxis de subcolumnas](/es/reference/data-types/newjson#reading-json-paths-as-sub-columns)
* `bit_count(bytea)`: [bitCount](/es/reference/functions/regular-functions/bit-functions#bitcount)
* `to_timestamp(float8)`: [fromUnixTimestamp](/es/reference/functions/regular-functions/date-time-functions#fromUnixTimestamp)
* `to_char(timestamp[tz], fmt)`: [formatDateTime](/es/reference/functions/regular-functions/date-time-functions#formatDateTime)
  cuando `fmt` es una constante de cadena y cada una de sus palabras clave tiene un equivalente fiel en
  ClickHouse. Consulte [to\_char()](#to_char) en las Notas de compatibilidad
  para ver las palabras clave admitidas. De lo contrario, la función se evalúa
  localmente en PostgreSQL.
* `statement_timestamp`, `transaction_timestamp`, & `clock_timestamp`:
  [nowInBlock64](/es/reference/functions/regular-functions/date-time-functions#nowInBlock64)
  (`nowInBlock64(9, $session_timezone)`)
* `CURRENT_DATE`:
  [now](/es/reference/functions/regular-functions/date-time-functions#now) y
  [toDate](/es/reference/functions/regular-functions/type-conversion-functions#toDate)
  (`toDate(now($session_timezone))`)
* `now`, `CURRENT_TIMESTAMP`, & `LOCALTIMESTAMP`:
  [now64](/es/reference/functions/regular-functions/date-time-functions#now64)
  (`now64(9, $session_timezone)`)
* `CURRENT_TIMESTAMP(n)` & `LOCALTIMESTAMP(n)`:
  [now64](/es/reference/functions/regular-functions/date-time-functions#now64)
  (`now64(n, $session_timezone)`)
* `CURRENT_DATABASE`: Se pasa como valor desde la función de PostgreSQL.
* `CURRENT_SCHEMA`: Se pasa como valor desde una función de PostgreSQL.
* `CURRENT_CATALOG`: Se pasa como valor de la función de PostgreSQL.
* `CURRENT_USER`: Se pasa como valor desde una función de PostgreSQL.
* `USER`: Se pasa como valor de la función de PostgreSQL.
* `CURRENT_ROLE`: Se pasa como valor de una función de PostgreSQL.
* `SESSION_USER`: Se pasa como valor desde una función de PostgreSQL.

<div id="pushdown-operators">
  ### Operadores de pushdown
</div>

* Segmento de Array (`arr[L:U]`): [arraySlice](/es/reference/functions/regular-functions/array-functions#arraySlice)
* `@>` (Array contiene): [hasAll](/es/reference/functions/regular-functions/array-functions#hasAll)
* `<@` (Array contenido en): [hasAll](/es/reference/functions/regular-functions/array-functions#hasAll)
* `&&` (solapamiento de Arrays): [hasAny](/es/reference/functions/regular-functions/array-functions#hasAny)
* `~` (coincidencia de regexp): [match](/es/reference/functions/regular-functions/string-search-functions#match)
* `!~` (sin coincidencia de regexp): [match](/es/reference/functions/regular-functions/string-search-functions#match)
* `~*` (regexp sin distinción entre mayúsculas y minúsculas sin coincidencia): [match](/es/reference/functions/regular-functions/string-search-functions#match)
* `!~*` (regexp sin distinción entre mayúsculas y minúsculas no coincide): [match](/es/reference/functions/regular-functions/string-search-functions#match)
* `->>` (JSON/JSONB extrae el elemento como texto): [sintaxis de sub-columnas](/es/reference/data-types/newjson#reading-json-paths-as-sub-columns)
* `->` (JSON/JSONB extrae): [toJSONString](/es/reference/functions/regular-functions/json-functions#toJSONString) + [sintaxis de sub-columnas](/es/reference/data-types/newjson#reading-json-paths-as-sub-columns)

<div id="custom-functions">
  ### Funciones personalizadas
</div>

Estas funciones personalizadas creadas por `pg_clickhouse` proporcionan pushdown de consultas externas
para determinadas funciones de ClickHouse que no tienen equivalentes en PostgreSQL. Si
alguna de estas funciones no se puede ejecutar mediante pushdown, generará una excepción.

* [dictGet](/es/reference/functions/regular-functions/ext-dict-functions#dictget-dictgetordefault-dictgetornull)

<div id="extension-pushdown">
  ### Pushdown de extensiones
</div>

pg\_clickhouse reconoce funciones de algunas extensiones principales y de terceros,
y las delega a sus equivalentes en ClickHouse.

<div id="re2">
  #### re2
</div>

Todas las funciones de la [extensión re2] se delegan 1:1 en ClickHouse:

* `re2match` → [match](/es/reference/functions/regular-functions/string-search-functions#match)
* `re2extract` → [extract](/es/reference/functions/regular-functions/string-search-functions#extract)
* `re2extractall` → [extractAll](/es/reference/functions/regular-functions/string-search-functions#extractAll)
* `re2regexpextract` → [regexpExtract](/es/reference/functions/regular-functions/string-search-functions#regexpExtract)
* `re2extractgroups` → [extractGroups](/es/reference/functions/regular-functions/string-search-functions#extractGroups)
* `re2replaceregexpone` → [replaceRegexpOne](/es/reference/functions/regular-functions/string-replace-functions#replaceRegexpOne)
* `re2replaceregexpall` → [replaceRegexpAll](/es/reference/functions/regular-functions/string-replace-functions#replaceRegexpAll)
* `re2countmatches` → [countMatches](/es/reference/functions/regular-functions/string-search-functions#countMatches)
* `re2countmatchescaseinsensitive` → [countMatchesCaseInsensitive](/es/reference/functions/regular-functions/string-search-functions#countMatchesCaseInsensitive)
* `re2multimatchany` → [multiMatchAny](/es/reference/functions/regular-functions/string-search-functions#multiMatchAny)
* `re2multimatchanyindex` → [multiMatchAnyIndex](/es/reference/functions/regular-functions/string-search-functions#multiMatchAnyIndex)
* `re2multimatchallindices` → [multiMatchAllIndices](/es/reference/functions/regular-functions/string-search-functions#multiMatchAllIndices)

<div id="intarray">
  #### intarray
</div>

Una función de [intarray] se delega en ClickHouse:

* `idx` → [indexOf](/es/reference/functions/regular-functions/array-functions#indexOf)

<div id="fuzzystrmatch">
  #### fuzzystrmatch
</div>

Dos funciones de [fuzzystrmatch] se delegan en ClickHouse:

* `soundex`: [soundex](/es/reference/functions/regular-functions/string-functions#soundex)
* `levenshtein` (2-arg): [editDistanceUTF8](/es/reference/functions/regular-functions/string-functions#editDistanceUTF8)

<div id="pushdown-casts">
  ### Conversiones de tipo pushdown
</div>

pg\_clickhouse hace pushdown de conversiones de tipo como `CAST(x AS bigint)` para
tipos de datos compatibles. En el caso de tipos incompatibles, el pushdown fallará; si `x` en este
ejemplo es un `UInt64` de ClickHouse, ClickHouse se negará a convertir el valor.

Para hacer pushdown de conversiones de tipo a tipos de datos incompatibles, pg\_clickhouse proporciona
las siguientes funciones. Generan una excepción en PostgreSQL si no se
ejecutan con pushdown.

* [toUInt8](/es/reference/functions/regular-functions/type-conversion-functions#touint8)
* [toUInt16](/es/reference/functions/regular-functions/type-conversion-functions#touint16)
* [toUInt32](/es/reference/functions/regular-functions/type-conversion-functions#touint32)
* [toUInt64](/es/reference/functions/regular-functions/type-conversion-functions#touint64)
* [toUInt128](/es/reference/functions/regular-functions/type-conversion-functions#touint128)

<div id="pushdown-aggregates">
  ### Agregaciones pushdown
</div>

Estas funciones de agregación de PostgreSQL admiten pushdown a ClickHouse.

* [array\_agg](/es/reference/functions/aggregate-functions/groupArray)
* [avg](/es/reference/functions/aggregate-functions/avg)
* [bit\_and](/es/reference/functions/aggregate-functions/groupBitAnd)
* [bit\_or](/es/reference/functions/aggregate-functions/groupBitOr)
* [bit\_xor](/es/reference/functions/aggregate-functions/groupBitXor)
* [bool\_and / every](/es/reference/functions/aggregate-functions/groupBitAnd)
* [bool\_or](/es/reference/functions/aggregate-functions/groupBitOr)
* [count](/es/reference/functions/aggregate-functions/count)
* [min](/es/reference/functions/aggregate-functions/min)
* [max](/es/reference/functions/aggregate-functions/max)
* [string\_agg](/es/reference/functions/aggregate-functions/groupConcat)
* [sum](/es/reference/functions/aggregate-functions/sum)

<div id="custom-aggregates">
  ### Agregaciones personalizadas
</div>

Estas funciones de agregación personalizadas creadas por `pg_clickhouse` proporcionan
pushdown de consultas externas para algunas funciones de agregación de ClickHouse que no
tienen equivalentes en PostgreSQL. Si alguna de estas funciones no puede aplicarse
mediante pushdown, generará una excepción.

* [argMax](/es/reference/functions/aggregate-functions/argMax)
* [argMin](/es/reference/functions/aggregate-functions/argMin)
* [uniq](/es/reference/functions/aggregate-functions/uniq)
* [uniqCombined](/es/reference/functions/aggregate-functions/uniqCombined)
* [uniqCombined64](/es/reference/functions/aggregate-functions/uniqCombined64)
* [uniqExact](/es/reference/functions/aggregate-functions/uniqExact)
* [uniqHLL12](/es/reference/functions/aggregate-functions/uniqHLL12)
* [uniqTheta](/es/reference/functions/aggregate-functions/uniqthetasketch)
* [quantile](/es/reference/functions/aggregate-functions/quantile)
* [quantileExact](/es/reference/functions/aggregate-functions/quantileExact)

<div id="pushdown-ordered-set-aggregates">
  ### Agregados de conjunto ordenado con pushdown
</div>

Estas \[funciones de agregado de conjunto ordenado] se corresponden con las [funciones de agregado paramétricas] de ClickHouse al pasar su *argumento directo* como parámetro y sus expresiones `ORDER BY` como argumentos. Por ejemplo, esta consulta de PostgreSQL:

```sql theme={null}
SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1;
```

Se corresponde con esta consulta de ClickHouse:

```sql theme={null}
SELECT quantile(0.25)(a) FROM t1;
```

Ten en cuenta que los sufijos no predeterminados de `ORDER BY`, `DESC` y `NULLS FIRST`,
no son compatibles y producirán un error.

* `percentile_cont(double)`: [quantile](/es/reference/functions/aggregate-functions/quantile)
* `quantile(double)`: [quantile](/es/reference/functions/aggregate-functions/quantile)
* `quantileExact(double)`: [quantileExact](/es/reference/functions/aggregate-functions/quantileExact)

<div id="pushdown-window-functions">
  ### Funciones de ventana con pushdown
</div>

Estas [funciones de ventana] de PostgreSQL se delegan en ClickHouse con cláusulas `OVER
(PARTITION BY ... ORDER BY ...)`, incluidas las especificaciones de frame cuando
corresponde.

* [row\_number](/es/reference/functions/window-functions#row_number)
* [rank](/es/reference/functions/window-functions#rank)
* [dense\_rank](/es/reference/functions/window-functions#dense_rank)
* [ntile](/es/reference/functions/window-functions#ntile)
* [cume\_dist](/es/reference/functions/window-functions#cume_dist)
* [percent\_rank](/es/reference/functions/window-functions#percent_rank)
* [lead](/es/reference/functions/window-functions#lead)
* [lag](/es/reference/functions/window-functions#lag)
* [first\_value](/es/reference/functions/window-functions#first_value)
* [last\_value](/es/reference/functions/window-functions#last_value)
* [nth\_value](/es/reference/functions/window-functions#nth_value)
* `min` / `max` (con cláusula `OVER`)

Las funciones de clasificación (`row_number`, `rank`, `dense_rank`, `ntile`, `cume_dist`,
`percent_rank`) omiten su cláusula de frame durante la delegación porque ClickHouse
rechaza las especificaciones de frame en estas funciones.

<div id="compatibility-notes">
  ## Notas de compatibilidad
</div>

<div id="regular-expressions">
  ### Expresiones regulares
</div>

Aunque pg\_clickhouse hace pushdown de las expresiones regulares a sus equivalentes de ClickHouse
cuando [pg\_clickhouse.pushdown\_regex](#pg_clickhousepushdown_regex) es true (el
valor predeterminado), y procura garantizar un nivel básico de compatibilidad, tenga
en cuenta las diferencias entre ambos y cómo las gestiona pg\_clickhouse.

* PostgreSQL admite [expresiones regulares POSIX], mientras que ClickHouse admite
  [expresiones regulares RE2][RE2]. Tenga en cuenta las diferencias de comportamiento: use RE2
  cuando la expresión regular vaya a evaluarse en ClickHouse (p. ej., en una
  cláusula `WHERE`) y POSIX cuando vaya a evaluarse en Postgres (p. ej., en una
  cláusula `SELECT`).

* pg\_clickhouse hace pushdown de los \[flags de regex] de Postgres anteponiéndolos a la
  expresión regular de ClickHouse dentro de `(?)`. Por ejemplo:

  ```sql theme={null}
  regexp_like(val, '^VAL\d', 'i')
  ```

  Se convierte en

  ```sql theme={null}
  match(val, concat('(?i-s)', '^VAL\\d'))
  ```

  Tenga en cuenta la inclusión de `-s`; esto alinea el comportamiento con las
  expresiones regulares de Postgres al desactivar `s`, que ClickHouse habilita de forma predeterminada.
  pg\_clickhouse no incluirá `-s` si los flags de la llamada a la función de Postgres
  incluyen `s`. Desafortunadamente, este comportamiento rompe la compatibilidad de
  algunas expresiones regulares en Postgres 24 y versiones anteriores.

* Los únicos flags que ambos admiten y que, por lo tanto, pueden usarse cuando se evalúan en
  ClickHouse son:

  * `i`: sin distinción entre mayúsculas y minúsculas
  * `m`: modo multilínea:
  * `s`: hace que `.` coincida con `\n`
  * `p`: coincidencia parcial sensible a saltos de línea (se trata igual que `s`)
  * `t`: sintaxis estricta (la predeterminada, eliminada por pg\_clickhouse)

  RE2 solo admite estos flags; no use ningún otro \[flag de Postgres]

* Cualquier otro flag pasado a funciones de expresiones regulares hará que la
  función no se envíe mediante pushdown.

* La excepción es `regexp_replace()`, que también admite el flag `g`. Cuando
  `g` está establecido, pg\_clickhouse usa `replaceRegexpAll()` en lugar de
  `replaceRegexpOne()` y elimina el flag antes de anteponer los demás flags.

* El argumento de reemplazo de `regexp_replace()` de Postgres admite `\&` para
  referirse a la coincidencia completa, mientras que ClickHouse usa `\0` para la
  coincidencia completa. Asegúrese de usar `\0` cuando la función se envíe mediante pushdown a ClickHouse.

Para evitar cualquier ambigüedad, considere establecer
[pg\_clickhouse.pushdown\_regex](#pg_clickhousepushdown_regex) para impedir que las
expresiones regulares de Postgres se envíen mediante pushdown a ClickHouse, y usar la
[extensión re2], para la cual pg\_clickhouse admite [pushdown directo](#re2) de
expresiones regulares [RE2] compatibles con ClickHouse.

<div id="to_char">
  ### `to_char()`
</div>

PostgreSQL [`to_char()`] para `timestamp` y `timestamp with time zone`
solo se delega a ClickHouse [formatDateTime] cuando el argumento de formato
es una string constant no `NULL` en la que cada palabra clave de PostgreSQL tiene un
equivalente en ClickHouse idéntico byte por byte. Si el formato es dinámico
(no es una `Const`), o contiene alguna palabra clave o modifier no compatible, la
llamada vuelve a evaluarse localmente en PostgreSQL; nunca se intenta delegar
con una traducción parcial, por lo que la salida sigue siendo compatible con PG.

Las formas de `to_char()` de dos argumentos sobre `numeric`, `interval` y otros
tipos que no son de timestamp nunca se delegan; ClickHouse [formatDateTime] solo
da formato a valores de fecha y hora.

<div id="translated-keywords">
  #### Palabras clave traducidas
</div>

| PostgreSQL                 | ClickHouse | Significado                                                  |
| -------------------------- | ---------- | ------------------------------------------------------------ |
| `YYYY`, `yyyy`             | `%Y`       | año de 4 dígitos                                             |
| `YY`, `yy`                 | `%y`       | año de 2 dígitos                                             |
| `MM`, `mm`                 | `%m`       | mes con ceros a la izquierda (01–12)                         |
| `DD`, `dd`                 | `%d`       | día del mes con ceros a la izquierda (01–31)                 |
| `DDD`, `ddd`               | `%j`       | día del año con ceros a la izquierda (001–366)               |
| `HH24`, `hh24`             | `%H`       | hora en formato de 24 horas con ceros a la izquierda (00–23) |
| `HH`, `hh`, `HH12`, `hh12` | `%I`       | hora en formato de 12 horas con ceros a la izquierda (01–12) |
| `MI`, `mi`                 | `%i`       | minuto con ceros a la izquierda (00–59)                      |
| `SS`, `ss`                 | `%S`       | segundo con ceros a la izquierda (00–59)                     |
| `Q`, `q`                   | `%Q`       | trimestre (1–4)                                              |
| `Mon`                      | `%b`       | nombre abreviado del mes, p. ej., `Oct`                      |
| `Dy`                       | `%a`       | nombre abreviado del día de la semana, p. ej., `Mon`         |
| `AM`, `PM`                 | `%p`       | indicador AM/PM, siempre en mayúsculas                       |

<div id="quoted-text-and-literals">
  #### Texto entre comillas y literales
</div>

El texto delimitado por `"..."` se conserva tal cual, y cualquier `%` literal
se duplica como `%%` para escapar el prefijo de especificador de ClickHouse. Un `\"` fuera de
las comillas también se conserva como un literal `"`. Dentro de `"..."`, la barra invertida
solo escapa `"`; las demás secuencias con barra invertida se tratan como texto literal.

<div id="authors">
  ## Autores
</div>

[David E. Wheeler](https://justatheory.com/)

<div id="copyright">
  ## Derechos de autor
</div>

Copyright (c) 2025-2026, ClickHouse

[foreign data wrapper]: https://www.postgresql.org/docs/current/fdwhandler.html "Documentación de PostgreSQL: Escritura de un foreign data wrapper"

[imagen de Docker]: https://github.com/ClickHouse/pg_clickhouse/pkgs/container/pg_clickhouse "Última versión en Docker Hub"

[ClickHouse]: https://clickhouse.com/clickhouse

[Control de versiones semántico]: https://semver.org/spec/v2.0.0.html "Control de versiones semántico 2.0.0"

[`pg_get_loaded_modules()`]: https://pgpedia.info/g/pg_get_loaded_modules.html "pgPedia: pg_get_loaded_modules()"

[DDL]: https://en.wikipedia.org/wiki/Data_definition_language "Wikipedia: lenguaje de definición de datos"

[CREATE EXTENSION]: https://www.postgresql.org/docs/current/sql-createextension.html "Documentación de PostgreSQL: CREATE EXTENSION"

[ALTER EXTENSION]: https://www.postgresql.org/docs/current/sql-alterextension.html "Documentación de PostgreSQL: ALTER EXTENSION"

[DROP EXTENSION]: https://www.postgresql.org/docs/current/sql-dropextension.html "Documentación de PostgreSQL: DROP EXTENSION"

[CREATE SERVER]: https://www.postgresql.org/docs/current/sql-createserver.html "Documentación de PostgreSQL: CREATE SERVER"

[ALTER SERVER]: https://www.postgresql.org/docs/current/sql-alterserver.html "Documentación de PostgreSQL: ALTER SERVER"

[DROP SERVER]: https://www.postgresql.org/docs/current/sql-dropserver.html "Documentación de PostgreSQL: DROP SERVER"

[CREATE USER MAPPING]: https://www.postgresql.org/docs/current/sql-createusermapping.html "Documentación de PostgreSQL: CREATE USER MAPPING"

[ALTER USER MAPPING]: https://www.postgresql.org/docs/current/sql-alterusermapping.html "Documentación de PostgreSQL: ALTER USER MAPPING"

[DROP USER MAPPING]: https://www.postgresql.org/docs/current/sql-dropusermapping.html "Documentación de PostgreSQL: DROP USER MAPPING"

[IMPORT FOREIGN SCHEMA]: https://www.postgresql.org/docs/current/sql-importforeignschema.html "Documentación de PostgreSQL: IMPORT FOREIGN SCHEMA"

[CREATE FOREIGN TABLE]: https://www.postgresql.org/docs/current/sql-createforeigntable.html "Documentación de PostgreSQL: CREATE FOREIGN TABLE"

[motor de tabla]: /reference/engines/table-engines "Documentación de ClickHouse: Motores de tabla"

[tipo AggregateFunction]: /reference/data-types/aggregatefunction "Documentación de ClickHouse: Tipo AggregateFunction"

[tipo SimpleAggregateFunction]: /reference/data-types/simpleaggregatefunction "Documentación de ClickHouse: Tipo SimpleAggregateFunction"

[ALTER FOREIGN TABLE]: https://www.postgresql.org/docs/current/sql-alterforeigntable.html "Documentación de PostgreSQL: ALTER FOREIGN TABLE"

[DROP FOREIGN TABLE]: https://www.postgresql.org/docs/current/sql-dropforeigntable.html "Documentación de PostgreSQL: DROP FOREIGN TABLE"

[DML]: https://en.wikipedia.org/wiki/Data_manipulation_language "Wikipedia: lenguaje de manipulación de datos"

[EXPLAIN]: https://www.postgresql.org/docs/current/sql-explain.html "Documentación de PostgreSQL: EXPLAIN"

[SELECT]: https://www.postgresql.org/docs/current/sql-select.html "Documentación de PostgreSQL: SELECT"

[PREPARE]: https://www.postgresql.org/docs/current/sql-prepare.html "Documentación de PostgreSQL: PREPARE"

[EXECUTE]: https://www.postgresql.org/docs/current/sql-execute.html "Documentación de PostgreSQL: EXECUTE"

[DEALLOCATE]: https://www.postgresql.org/docs/current/sql-deallocate.html "Documentación de PostgreSQL: DEALLOCATE"

[PREPARE]: https://www.postgresql.org/docs/current/sql-prepare.html "Documentación de PostgreSQL: PREPARE"

[INSERT]: https://www.postgresql.org/docs/current/sql-insert.html "Documentación de PostgreSQL: INSERT"

[COPY]: https://www.postgresql.org/docs/current/sql-copy.html "Documentación de PostgreSQL: COPY"

[LOAD]: https://www.postgresql.org/docs/current/sql-load.html "Documentación de PostgreSQL: LOAD"

[SET]: https://www.postgresql.org/docs/current/sql-set.html "Documentación de PostgreSQL: SET"

[ALTER ROLE]: https://www.postgresql.org/docs/current/sql-alterrole.html "Documentación de PostgreSQL: ALTER ROLE"

[precarga de bibliotecas compartidas]: https://www.postgresql.org/docs/current/runtime-config-client.html#RUNTIME-CONFIG-CLIENT-PRELOAD "Documentación de PostgreSQL: Precarga de bibliotecas compartidas"

[funciones de agregado de conjuntos ordenados]: https://www.postgresql.org/docs/current/functions-aggregate.html#FUNCTIONS-ORDEREDSET-TABLE

[Funciones de agregado paramétricas]: /reference/functions/aggregate-functions/parametric-functions

[configuración de ClickHouse]: /reference/settings/session-settings "Documentación de ClickHouse: Configuración de la sesión"

[delimitación con dólar]: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING "Documentación de PostgreSQL: constantes de cadena delimitadas con dólar"

[notas sobre PREPARE]: https://www.postgresql.org/docs/current/sql-prepare.html#SQL-PREPARE-NOTES "Documentación de PostgreSQL: notas sobre PREPARE"

[parámetros de consulta]: /guides/clickhouse/data-modelling/stored-procedures-and-prepared-statements#alternatives-to-prepared-statements-in-clickhouse "Documentación de ClickHouse: alternativas a las sentencias preparadas en ClickHouse"

[error subyacente]: https://github.com/ClickHouse/ClickHouse/issues/85847 "ClickHouse/ClickHouse#85847 Algunas consultas en formularios multipart no leen la configuración"

[solucionado]: https://github.com/ClickHouse/ClickHouse/pull/85570 "ClickHouse/ClickHouse#85570 corrige HTTP con multipart"

[BYTEA]: https://www.postgresql.org/docs/current/datatype-binary.html "Documentación de PostgreSQL: tipos de datos binarios"

[GRANT]: https://www.postgresql.org/docs/current/sql-grant.html "Documentación de PostgreSQL: GRANT"

[String]: /reference/data-types/string "Documentación de ClickHouse: String"

[TEXT]: https://www.postgresql.org/docs/current/datatype-character.html "Documentación de PostgreSQL: tipos de caracteres"

[funciones de ventana]: https://www.postgresql.org/docs/current/functions-window.html "Documentación de PostgreSQL: funciones de ventana"

[Expresiones regulares POSIX]: https://www.postgresql.org/docs/18/functions-matching.html#FUNCTIONS-POSIX-REGEXP "Documentación de PostgreSQL: expresiones regulares POSIX"

[modificadores de Postgres]: https://www.postgresql.org/docs/18/functions-matching.html#POSIX-EMBEDDED-OPTIONS-TABLE "Documentación de PostgreSQL: letras de opciones incrustadas de ARE"

[RE2]: https://github.com/google/re2/wiki/Syntax "Sintaxis de RE2"

[extensión re2]: https://github.com/ClickHouse/pg_re2 "pg_re2: funciones de expresiones regulares compatibles con ClickHouse que usan RE2"

[intarray]: https://www.postgresql.org/docs/current/intarray.html "Documentación de PostgreSQL: intarray"

[fuzzystrmatch]: https://www.postgresql.org/docs/current/fuzzystrmatch.html "Documentación de PostgreSQL: fuzzystrmatch"

[`to_char()`]: https://www.postgresql.org/docs/current/functions-formatting.html "Documentación de PostgreSQL: funciones de formato de tipos de datos"

[formatDateTime]: /reference/functions/regular-functions/date-time-functions#formatDateTime "Documentación de ClickHouse: formatDateTime"
