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

# Run SQL query with AWS Athena

export const Comments = ({children}) => {
  return <div class="my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border border-zinc-500/20 bg-zinc-50/50 dark:border-zinc-500/30 dark:bg-zinc-500/10" data-callout-type="comments">
      <div class="w-4">
        <svg width="14" height="14" viewBox="0 0 640 640" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" aria-label="Comments">
            <path d="M320 112C434.9 112 528 205.1 528 320C528 434.9 434.9 528 320 528C205.1 528 112 434.9 112 320C112 205.1 205.1 112 320 112zM320 576C461.4 576 576 461.4 576 320C576 178.6 461.4 64 320 64C178.6 64 64 178.6 64 320C64 461.4 178.6 576 320 576zM280 400C266.7 400 256 410.7 256 424C256 437.3 266.7 448 280 448L360 448C373.3 448 384 437.3 384 424C384 410.7 373.3 400 360 400L352 400L352 312C352 298.7 341.3 288 328 288L280 288C266.7 288 256 298.7 256 312C256 325.3 266.7 336 280 336L304 336L304 400L280 400zM320 256C337.7 256 352 241.7 352 224C352 206.3 337.7 192 320 192C302.3 192 288 206.3 288 224C288 241.7 302.3 256 320 256z" />
        </svg>
      </div>
      <div class="text-sm prose min-w-0 w-full">
        {children}
      </div>
    </div>;
};

You can query data in S3 with SQL directly from a Metaflow task, using the same AWS tools you would use in any Python script. This page uses [AWS Glue](https://aws.amazon.com/glue/) and [AWS Athena](https://aws.amazon.com/athena/): AWS Glue is a managed extract, transform, and load (ETL) service, and AWS Athena is a serverless SQL service that runs queries against Glue databases.

<Steps>
  <Step title="Add parquet files to an AWS Glue database">
    The following utility function creates the Glue database and writes a small dataset to S3 as `.parquet` files. AWS Glue works with many other data formats as well.

    ```py title="create_glue_db.py" expandable theme={null}
    import pandas as pd
    import awswrangler as wr

    def create_db(database_name, bucket_uri, table_name):
        dataset = pd.DataFrame({
            "id": [1, 2],
            "feature_1": ["foo", "bar"],
            "feature_2": ["fizz", "buzz"]}
        )

        try: 
            # Create an AWS Glue database to query S3 data
            wr.catalog.create_database(name=database_name)
        except wr.exceptions.AlreadyExists as error:
            # If the database exists, ignore this step
            print(f"{database_name} exists!")

        # Store data in the AWS data lake.
        # This example uses .parquet files, but
        # AWS Glue works with many other data formats.
        _ = wr.s3.to_parquet(df=dataset, 
                             path=f"{bucket_uri}/dataset/",
                             dataset=True, 
                             database=database_name,
                             table=table_name)
    ```
  </Step>

  <Step title="Run the flow">
    This flow shows how to:

    * Access parquet data with a SQL query using AWS Athena.
    * Transform a dataset.
    * Write a pandas dataframe to AWS S3 as `.parquet` files.

    ```py title="sql_query_athena.py" expandable theme={null}
    from metaflow import FlowSpec, step, Parameter
    import awswrangler as wr
    from create_glue_db import create_db

    class AWSQueryFlow(FlowSpec):
        
        bucket_uri = Parameter(
                        "bucket_uri", 
                        default="<BUCKET_URI>"
                     )
        db_name = Parameter("database_name", 
                            default="test_db")
        table_name = Parameter("table_name", 
                               default="test_table")

        @step
        def start(self):
            create_db(self.db_name, self.bucket_uri, 
                      self.table_name)
            self.next(self.query)

        @step
        def query(self):
            QUERY = f"SELECT * FROM {self.table_name}"
            result = wr.athena.read_sql_query(
                QUERY, 
                database=self.db_name
            )
            self.dataset = result
            self.next(self.transform)
            
        @step
        def transform(self):
            concat = lambda x: x["feature_1"] + x["feature_2"]
            self.dataset["feature_12"] = self.dataset.apply(
                concat, 
                axis=1
            )
            self.next(self.write)
            
        @step
        def write(self):
            path = f"{self.bucket_uri}/dataset/"
            _ = wr.s3.to_parquet(df=self.dataset, 
                                 mode="overwrite",
                                 path=path,
                                 dataset=True, 
                                 database=self.db_name,
                                 table=self.table_name)
            self.next(self.end)
            
        @step
        def end(self):
            print("Database is updated!")

    if __name__ == '__main__':
        AWSQueryFlow()
    ```

    <Comments>
      Replace \<BUCKET\_URI> with the URI of your S3 bucket, such as `s3://my-bucket`.
    </Comments>

    ```bash theme={null}
    python sql_query_athena.py run
    ```

    ```text theme={null}
        ...
         [106/extract/481 (pid 8240)] Task is starting.
         [106/extract/481 (pid 8240)] Task finished successfully.
        ...
         [106/transform/482 (pid 8244)] Task is starting.
         [106/transform/482 (pid 8244)] Task finished successfully.
        ...
         [106/write/483 (pid 8249)] Task is starting.
         [106/write/483 (pid 8249)] Task finished successfully.
        ...
         [106/end/484 (pid 8253)] Task is starting.
         [106/end/484 (pid 8253)] Database is updated!
         [106/end/484 (pid 8253)] Task finished successfully.
        ...
    ```
  </Step>

  <Step title="Access artifacts outside of the flow">
    Run the following in any script or notebook to access the contents of the dataframe that was stored as a flow artifact with `self.dataset`:

    ```python theme={null}
    from metaflow import Flow
    run_data = Flow('AWSQueryFlow').latest_run.data
    run_data.dataset
    ```

    ```text theme={null}
       id feature_1 feature_2 feature_12
    0   1       foo      fizz    foofizz
    1   2       bar      buzz    barbuzz
    ```
  </Step>
</Steps>
