> For the complete documentation index, see [llms.txt](https://ciusji.gitbook.io/luden/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ciusji.gitbook.io/luden/features/data-warehouses.md).

# Data Warehouses

Luden supports the following Data Warehouses (DWH) as destinations:

* [Postgres SQL](#postgres-sql)
* [ClickHouse](#clickhouse)
* [Redshift](#redshift)
* [Snowflake](#snowflake)
* [BigQuery](#bigquery)
* [MySQL](#mysql)

This article explains which features are available for each DWH and implementation details.

## Postgres SQL

<table><thead><tr><th width="227.33333333333331">Feature</th><th width="134">Status</th><th>Details</th></tr></thead><tbody><tr><td>Push events (API keys)<br><strong>stream mode</strong></td><td>Supported</td><td><strong>If destination table has primary key:</strong><br><code>INSERT INTO destination_table(...) VALUES ... ON CONFLICT ON CONSTRAINT primary_key DO UPDATE SET ...</code><br><strong>If destination table has no primary key:</strong><br><code>INSERT INTO destination_table(...) VALUES ...</code></td></tr><tr><td>Push events (API keys)<br><strong>batch mode</strong></td><td>Supported</td><td><strong>If destination table has primary key:</strong><br>In SQL transaction:<br>1. create <code>tmp_table</code><br>2. insert multiple rows into <code>tmp_table</code><br>3. insert from tmp_table: <code>INSERT INTO destination_table(...) SELECT ... FROM tmp_table ON CONFLICT ON CONSTRAINT primary_key DO UPDATE SET ...</code><br>4. delete <code>tmp_table</code><br><br><strong>If destination table has no primary key:</strong><br>In SQL transaction:<br>1. insert multiple rows into destination table</td></tr><tr><td>Pull events (Sources)</td><td>Supported*</td><td>*JavaScript Transformation currently not applied to pulled data<br><br>In SQL transaction:<br>1. Delete previous data for current sync interval: <code>DELETE FROM destination_table WHERE _time_interval=?</code><br>2. See <strong>Push events (API keys) batch mode</strong></td></tr><tr><td>User Recognition<br><strong>stream mode</strong></td><td>Supported</td><td>Primary key on <code>eventn_ctx_event_id</code> field is required for destination table.<br><code>UPDATE destination_table SET .. WHERE eventn_ctx_event_id=?</code></td></tr><tr><td>User Recognition<br><strong>batch mode</strong></td><td>Supported</td><td>Primary key on <code>eventn_ctx_event_id</code> field is required for destination table.<br>Same as <strong>Push events (API keys) batch mode</strong></td></tr></tbody></table>

## ClickHouse

<table><thead><tr><th width="231.33333333333331">Feature</th><th width="135">Status</th><th>Details</th></tr></thead><tbody><tr><td>Push events (API keys)<br><strong>stream mode</strong></td><td>Supported</td><td><code>INSERT INTO destination_table (...) VALUES ...</code></td></tr><tr><td>Push events (API keys)<br><strong>batch mode</strong></td><td>Supported</td><td><code>INSERT INTO destination_table (...) VALUES ...</code></td></tr><tr><td>Pull events (Sources)</td><td>Supported*</td><td>*JavaScript Transformation currently not applied to pulled data<br><br>1. Delete previous data for current sync interval: <code>ALTER TABLE destination_table DELETE WHERE _time_interval=?</code><br>2. See <strong>Push events (API keys) batch mode</strong></td></tr><tr><td>User Recognition<br><strong>stream mode</strong></td><td>Supported*</td><td><code>INSERT INTO destination_table (...) VALUES ...</code></td></tr><tr><td>User Recognition<br><strong>batch mode</strong></td><td>Supported*</td><td><code>INSERT INTO destination_table (...) VALUES ...</code></td></tr></tbody></table>

## Redshift

<table><thead><tr><th width="233.33333333333331">Feature</th><th width="131">Status</th><th>Details</th></tr></thead><tbody><tr><td>Push events (API keys)<br><strong>stream mode</strong></td><td>Supported</td><td><code>INSERT INTO destination_table(...) VALUES ...</code></td></tr><tr><td>Push events (API keys)<br><strong>batch mode</strong></td><td>Supported</td><td>1. Upload file with data to S3<br>2. Copy data from S3 to destination table: <code>copy destination_table from 's3://...'</code><br>3. Delete data from S3</td></tr><tr><td>Pull events (Sources)</td><td>Supported*</td><td>*JavaScript Transformation currently not applied to pulled data<br><br><strong>If destination table has primary key:</strong><br>In SQL transaction:<br>1. Delete previous data for current sync interval: <code>DELETE FROM destination_table WHERE _time_interval=?</code><br>2. create <code>tmp_table</code><br>3. insert multiple rows into <code>tmp_table</code><br>4. delete from destination table duplicated rows <code>DELETE FROM destination_table using tmp_table where primary_key_columns=?</code> .<br>5. insert from tmp_table: <code>INSERT INTO destination_table (...) select ... from tmp_table</code><br>6. delete <code>tmp_table</code><br><br><strong>If destination table has no primary key:</strong><br>In SQL transaction:<br>1. Delete previous data for current sync interval: <code>DELETE FROM destination_table WHERE _time_interval=?</code><br>2. insert multiple rows into destination table</td></tr><tr><td>User Recognition<br><strong>stream mode</strong></td><td>Supported</td><td>Primary key on <code>eventn_ctx_event_id</code> field is required for destination table.<br><code>UPDATE destination_table SET .. WHERE eventn_ctx_event_id=?</code></td></tr><tr><td>User Recognition<br><strong>batch mode</strong></td><td>Supported</td><td>Primary key on <code>eventn_ctx_event_id</code> field is required for destination table.<br>In SQL transaction:<br>1. create <code>tmp_table</code><br>2. insert multiple rows into <code>tmp_table</code><br>3. delete from destination table duplicated rows <code>DELETE FROM destination_table using tmp_table where eventn_ctx_event_id=?</code> .<br>4. insert from tmp_table: <code>INSERT INTO destination_table (...) select ... from tmp_table</code><br>5. delete <code>tmp_table</code></td></tr></tbody></table>

## Snowflake

<table><thead><tr><th width="234.33333333333331">Feature</th><th width="137">Status</th><th>Details</th></tr></thead><tbody><tr><td>Push events (API keys)<br><strong>stream mode</strong></td><td>Supported</td><td><code>INSERT INTO destination_table(...) VALUES ...</code></td></tr><tr><td>Push events (API keys)<br><strong>batch mode</strong></td><td>Supported</td><td><strong>S3</strong>:<br>1. Upload file with data to S3<br>2. Copy data from S3 to destination table: <code>copy into destination_table (...) from 's3://...'</code><br>3. Delete data from S3<br><br><strong>Google Cloud Storage</strong>:<br>1. Upload file with data to GCS<br>2. Copy data from GCS to destination table: <code>copy into destination_table (...) from @...</code><br>3. Delete data from GCS</td></tr><tr><td>Pull events (Sources)</td><td>Supported*</td><td>*JavaScript Transformation currently not applied to pulled data<br><br><strong>If destination table has primary key:</strong><br>In SQL transaction:<br>1. Delete previous data for current sync interval: <code>DELETE FROM destination_table WHERE _time_interval=?</code><br>2. create <code>tmp_table</code><br>3. insert multiple rows into <code>tmp_table</code><br>4. merge into destination table: <code>MERGE INTO destination_table USING (SELECT ... FROM tmp_table) ON primary_key_columns=? WHEN MATCHED THEN UPDATE SET ... WHEN NOT MATCHED THEN INSERT (...) VALUES (...)</code><br>5. delete <code>tmp_table</code><br><br><strong>If destination table has no primary key:</strong><br>In SQL transaction:<br>1. Delete previous data for current sync interval: <code>DELETE FROM destination_table WHERE _time_interval=?</code><br>2. insert multiple rows into destination table</td></tr><tr><td>User Recognition<br><strong>stream mode</strong></td><td>Supported</td><td>Primary key on <code>eventn_ctx_event_id</code> field is required for destination table.<br><code>UPDATE destination_table SET .. WHERE eventn_ctx_event_id=?</code></td></tr><tr><td>User Recognition<br><strong>batch mode</strong></td><td>Supported</td><td>Primary key on <code>eventn_ctx_event_id</code> field is required for destination table.<br>In SQL transaction:<br>1. Delete previous data for current sync interval: <code>DELETE FROM destination_table WHERE _time_interval=?</code><br>2. create <code>tmp_table</code><br>3. insert multiple rows into <code>tmp_table</code><br>4. merge into destination table: <code>MERGE INTO destination_table USING (SELECT ... FROM tmp_table) ON eventn_ctx_event_id=? WHEN MATCHED THEN UPDATE SET ... WHEN NOT MATCHED THEN INSERT (...) VALUES (...)</code><br>5. delete <code>tmp_table</code></td></tr></tbody></table>

## BigQuery

<table><thead><tr><th width="236.33333333333331"></th><th width="142"></th><th></th></tr></thead><tbody><tr><td>Feature</td><td>Status</td><td>Details</td></tr><tr><td>Push events (API keys)<br><strong>stream mode</strong></td><td>Supported</td><td>Insert using bigquery API</td></tr><tr><td>Push events (API keys)<br><strong>batch mode</strong></td><td>Supported</td><td>1. Upload file with data to GCS<br>2. Copy data from GCS to destination table using bigquery API<br>3. Delete data from GCS</td></tr><tr><td>Pull events (Sources)</td><td>Not supported</td><td></td></tr><tr><td>User Recognition<br><strong>stream mode</strong></td><td>Not supported</td><td></td></tr><tr><td>User Recognition<br><strong>batch mode</strong></td><td>Not supported</td><td></td></tr></tbody></table>

## MySQL

<table><thead><tr><th width="239.33333333333331">Feature</th><th width="140">Status</th><th>Details</th></tr></thead><tbody><tr><td>Push events (API keys)<br><strong>stream mode</strong></td><td>Supported</td><td><strong>If destination table has primary key:</strong><br><code>INSERT INTO destination_table(...) VALUES ... ON DUPLICATE KEY UPDATE ...</code><br><strong>If destination table has no primary key:</strong><br><code>INSERT INTO destination_table(...) VALUES ...</code></td></tr><tr><td>Push events (API keys)<br><strong>batch mode</strong></td><td>Supported</td><td><strong>If destination table has primary key:</strong><br>In SQL transaction:<br>1. create <code>tmp_table</code><br>2. insert multiple rows into <code>tmp_table</code><br>3. insert from tmp_table: <code>INSERT INTO destination_table(...) SELECT * FROM (SELECT ... FROM tmp_table) AS tmp ON DUPLICATE KEY UPDATE ...</code><br>4. delete <code>tmp_table</code><br><br><strong>If destination table has no primary key:</strong><br>In SQL transaction:<br>1. insert multiple rows into destination table</td></tr><tr><td>Pull events (Sources)</td><td>Supported*</td><td>*JavaScript Transformation currently not applied to pulled data<br><br>In SQL transaction:<br>1. Delete previous data for current sync interval: <code>DELETE FROM destination_table WHERE _time_interval=?</code><br>2. See <strong>Push events (API keys) batch mode</strong></td></tr><tr><td>User Recognition<br><strong>stream mode</strong></td><td>Supported</td><td>Primary key on <code>eventn_ctx_event_id</code> field is required for destination table.<br><code>UPDATE destination_table SET .. WHERE eventn_ctx_event_id=?</code></td></tr><tr><td>User Recognition<br><strong>batch mode</strong></td><td>Supported</td><td>Primary key on <code>eventn_ctx_event_id</code> field is required for destination table.<br>Same as <strong>Push events (API keys) batch mode</strong></td></tr></tbody></table>
