> ## Documentation Index
> Fetch the complete documentation index at: https://domoinc-openapi-sync-dataflows.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating a Recursive/Snapshot Old Magic ETL DataFlow

A "recursive" or "snapshot" DataFlow is a DataFlow that uses itself as an input.

DataFlows (neither SQL nor Magic ETL types) cannot append data natively like connectors. However, if you need to create a DataFlow that appends data, you can do so by running it once and then using the output as part of the input for the next run. This way, every time the DataFlow runs, it includes the data from before and also appends the new data onto itself.

<Warning>
  **Important:** If a recursive DataFlow is edited incorrectly, you could lose ALL historical data. To avoid this any time you are editing, create an additional DataSet that is a copy of your historical DataSet. This DataSet will remain static. If anything happens to your historical DataSet, you will have a backup from before you began editing.
</Warning>

**Video - What is a Recursive DataFlow?**

<iframe allowfullscreen="allowfullscreen" frameborder="0" height="315" src="//www.youtube-nocookie.com/embed/VkM5VznEzi8" width="560" />

**To create a recursive DataFlow in Magic ETL,**

1. Create and run a Magic ETL DataFlow.

   <Frame>
     <img alt="recursive_etl1.png" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOw3.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=fa9cc6d9b019f6b71d152b4da4ced07f" style={{width: 800, height: 387}} width="2384" height="1154" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOw3.png" />
   </Frame>
2. Once the DataFlow has finished running, load the output DataSet as an input DataSet.

   The DataSet name will show the output DataSet name followed by "1."

   <Frame>
     <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOw2.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=a6bd93282a5bdd7e6ac2ceb4a4c203c3" style={{width: 800, height: 312}} width="2372" height="926" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOw2.png" />
   </Frame>

   You should now have two DataSets in the DataFlow—the updating original DataSet and the historical DataSet.

   You now need to find a column to use as a constraint. This helps determine when to replace data in your historical DataSet with new data. Constraint columns are normally ID columns or date columns or have other unique identifiers. In this example we use the `Date` column as a constraint.
3. Use **Select Columns** to select only the constraint column.

   <Frame>
     <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvx.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=f912c98425575d4dcfccc16749065e24" style={{width: 800, height: 521}} width="1746" height="1138" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvx.png" />
   </Frame>
4. Use **Remove Duplicates** to return a unique list of constraints.

   <Frame>
     <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvu.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=de80d3f79d0fd933386ce9c55e8e7504" width="696" height="651" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvu.png" />
   </Frame>
5. Use **Add Constants** to create a new column that tells you when a row needs to be deleted.

   <Frame>
     <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvz.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=2e91a329807eee7eb893ef6fd3e1752c" style={{width: 799, height: 503}} width="1802" height="1134" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvz.png" />
   </Frame>
6. Use an Outer Join to join your deletion-identifying column to the unique constraint column in your historical DataSet.  If you selected the historical DataSet on the left side of the join, as shown below, use a left outer join. If you select the historical DataSet on the right side of the join, use a right outer join. (Do not select **Inner Join**, as this could result in a loss of data.)

   <Columns>
     <Frame>
       <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOw1.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=97c8602e4fdb9e693c4732557baf144f" style={{width: 801, height: 514}} width="1738" height="1116" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOw1.png" />
     </Frame>

     <Frame>
       <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOv3.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=07a6f76a0f6971dff4580d018d927820" style={{width: 801, height: 549}} width="1817" height="1245" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOv3.png" />
     </Frame>
   </Columns>
7. Filter any rows from your DataSet that contain the value "Delete Me" (or whatever identifier you came up with in step 5).

   This returns only rows from the historical DataSet that do not exist in the new updating DataSet.

   <Frame>
     <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvw.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=fdee7bd25844e0a7066e061007d6366f" style={{width: 799, height: 519}} width="1764" height="1146" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvw.png" />
   </Frame>
8. Use **Select Columns** to remove the additional unique constraint column (`Date`) and the unique deletion-identifying column.

   <Frame>
     <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvv.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=b3c5834ad6eb997a5d6554f3080780d2" style={{width: 801, height: 558}} width="1738" height="1212" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvv.png" />
   </Frame>
9. Use **Append** to join the historical DataSet and new updating DataSet.

   If all steps have been done correctly, both DataSets will show "No changes."

   <Frame>
     <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvy.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=016184152a49c46414545494c05b98f7" style={{width: 801, height: 562}} width="1782" height="1252" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOvy.png" />
   </Frame>
10. Connect the **Append** tile to your output.

Once complete, your Magic ETL should look like the following:

<Frame>
  <img alt="" src="https://mintcdn.com/domoinc-openapi-sync-dataflows/Bg_tFGvM-8KJbsB4/images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOw0.png?fit=max&auto=format&n=Bg_tFGvM-8KJbsB4&q=85&s=d0e4ea264dea8953d290f1d6037594a0" style={{width: 801, height: 383}} width="1796" height="860" data-path="images/kb/ka0Vq000000GnEU-00N5w00000Ri7BU-0EM5w000005vOw0.png" />
</Frame>

### Troubleshooting/FAQ

See [DataFlow Troubleshooting](https://domo-support.domo.com/s/article/360043427953?language=en_US) for resolutions to common issues.
