> ## Documentation Index
> Fetch the complete documentation index at: https://www.integrate.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# ETL: Moving Data Incrementally Between Databases

> This article guides you through the process of extracting and loading data incrementally from a database table to another database table.

This article guides you through the process of [extracting and loading data incrementally](https://www.integrate.io/blog/7-data-migration-best-practices/) from a database table to another database table. The concepts described in this article can also be applied to MongoDB.

## Reading Increments From the Source Table

When using Integrate.io ETL to read data incrementally from the source, we need a timestamp column that specifies when the data was updated (or inserted in tables where data is only inserted). In our example, this column is called "updated\_at". When reading from the source table, we'll use a **where clause** to only read the rows that were updated since the last time the package executed. It is highly recommended to index this column to improve the performance of the read query. For example, with PostgreSQL as the source, we can use the following **where clause,** in which \$last\_updated\_at is a package variable and is placed within a string for casting to a PostgreSQL timestamp value:

```sql theme={null}
updated_at > '$last_updated_at'::timestamp
```

<Frame>
  <img src="https://mintcdn.com/integrateio/fpWCvrjvoCDC-WOb/images/how-do-i/image-8.webp?fit=max&auto=format&n=fpWCvrjvoCDC-WOb&q=85&s=b7e82762b9f49b2d79509a3cf7d8fc45" alt="Database source component with a where clause using a timestamp variable" width="1098" height="1006" data-path="images/how-do-i/image-8.webp" />
</Frame>

<Note>
  Note that the schema detection or data preview fails when using the variable in the **where clause,** as variables are not evaluated in design time. So what value (or rather evaluated expression) should we assign to the package variable? There are two options:
</Note>

1. Use the predefined variable \_PACKAGE\_LAST\_SUCCESSFUL\_JOB\_SUBMISSION\_TIMESTAMP which returns the submission timestamp for the last successful execution of the package. Wrap the variable with a CASE statement to handle empty values and to allow full load if required.
   | Package variable name | Code                                                                                                                                                                                       |
   | :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   | full\_load            | `0`                                                                                                                                                                                        |
   | last\_updated\_at     | `CASE WHEN (COALESCE($_PACKAGE_LAST_SUCCESSFUL_JOB_SUBMISSION_TIMESTAMP,'')=='' OR $full_load==1) THEN '1900-01-01T00:00:00Z' ELSE $_PACKAGE_LAST_SUCCESSFUL_JOB_SUBMISSION_TIMESTAMP END` |
   <Frame>
     <img src="https://mintcdn.com/integrateio/fpWCvrjvoCDC-WOb/images/how-do-i/image-9.webp?fit=max&auto=format&n=fpWCvrjvoCDC-WOb&q=85&s=5f605d0dcb94575b24726509f5055e8f" alt="Package variables using CASE and COALESCE for last_updated_at" width="1016" height="335" data-path="images/how-do-i/image-9.webp" />
   </Frame>
2. Use the ExecuteSQL\* functions (such as [ExecuteSqlDateTime](/etl/executesqldatetime/)) to execute a query on the target database to get the max (last) value of updated\_at in the target. This may be more accurate than the first option, but it requires an extra query on the destination.
   | Package variable name | Code                                                                                                     |
   | :-------------------- | :------------------------------------------------------------------------------------------------------- |
   | full\_load            | `0`                                                                                                      |
   | last\_updated\_at     | `CASE WHEN (COALESCE($max_date,'')=='' OR $full_load==1) THEN '1900-01-01T00:00:00Z' ELSE $max_date END` |
   | max\_date             | `ExecuteSqlDateTime('REDSHIFT_CONNECTION_442','SELECT MAX(updated_at) FROM users')`                      |
   <Frame>
     <img src="https://mintcdn.com/integrateio/HSGmKiO3soPLENmi/images/how-do-i/image-10.webp?fit=max&auto=format&n=HSGmKiO3soPLENmi&q=85&s=d5c30ca415a64bae6408fe3d622e4cfb" alt="Package variables using ExecuteSqlDateTime to get max updated_at" width="1016" height="357" data-path="images/how-do-i/image-10.webp" />
   </Frame>

## Writing Increments to the Destination Table

Writing increments to the destination (Redshift on any other relational database) is fairly straightforward. If the increments read from the source are for newly appended data only (no updates), you can simply append the data to the destination table.

<Frame>
  <img src="https://mintcdn.com/integrateio/HSGmKiO3soPLENmi/images/how-do-i/image-11.webp?fit=max&auto=format&n=HSGmKiO3soPLENmi&q=85&s=ae3697fd6699eeff3e2c4f7ae86b6d02" alt="Destination component configured to append data to the target table" width="1096" height="1003" data-path="images/how-do-i/image-11.webp" />
</Frame>

If the increments also contain new changes to existing rows in the source table, you should define the **operation type** as **Merge** and select a primary **key** to find records that changed.

<Frame>
  <img src="https://mintcdn.com/integrateio/HSGmKiO3soPLENmi/images/how-do-i/image-12.webp?fit=max&auto=format&n=HSGmKiO3soPLENmi&q=85&s=2e51d316e77fef4d0fb5aca780ce0d28" alt="Destination component with Merge operation type and primary key selected" width="1098" height="1006" data-path="images/how-do-i/image-12.webp" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/integrateio/HSGmKiO3soPLENmi/images/how-do-i/image-13.webp?fit=max&auto=format&n=HSGmKiO3soPLENmi&q=85&s=ce5b80d34b053d7d901672d7bfca3d5d" alt="Merge operation schema mapping for incremental updates" width="1099" height="1007" data-path="images/how-do-i/image-13.webp" />
</Frame>
