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

# Transpose Columns

export const ComponentMetadata = ({warehouses, unsupportedWarehouses = [], componentType, connectionInputs, connectionOutputs}) => {
  const allWarehouses = [...warehouses.map(w => ({
    name: w,
    supported: true
  })), ...unsupportedWarehouses.map(w => ({
    name: w,
    supported: false
  }))];
  return <div style={{
    background: 'var(--colors-background-light, #f9fafb)',
    border: '1px solid var(--colors-border-default, #e5e7eb)',
    borderRadius: '12px',
    padding: '20px 28px',
    marginBottom: '28px',
    boxShadow: '0 1px 4px rgba(0,0,0,0.10)'
  }}>
      <table style={{
    width: '100%',
    borderCollapse: 'collapse'
  }}>
        <tbody>
          <tr>
            <td style={{
    fontWeight: '600',
    paddingRight: '32px',
    paddingBottom: '14px',
    whiteSpace: 'nowrap',
    verticalAlign: 'middle',
    width: '180px'
  }}>Project Availability</td>
            <td style={{
    paddingBottom: '14px',
    verticalAlign: 'middle'
  }}>
              <div style={{
    display: 'flex',
    flexWrap: 'wrap',
    gap: '8px'
  }}>
                {allWarehouses.map((w, i) => <span key={i} style={{
    background: w.supported ? '#dcfce7' : '#fee2e2',
    color: w.supported ? '#15803d' : '#b91c1c',
    border: `1px solid ${w.supported ? '#bbf7d0' : '#fca5a5'}`,
    borderRadius: '9999px',
    padding: '3px 12px',
    fontSize: '0.85rem',
    fontWeight: '500',
    whiteSpace: 'nowrap'
  }}>
                    {w.name} {w.supported ? '✅' : '❌'}
                  </span>)}
              </div>
            </td>
          </tr>
          <tr>
            <td style={{
    fontWeight: '600',
    paddingRight: '32px',
    paddingBottom: '14px',
    whiteSpace: 'nowrap',
    verticalAlign: 'middle'
  }}>Component Type</td>
            <td style={{
    paddingBottom: '14px',
    verticalAlign: 'middle'
  }}>{componentType}</td>
          </tr>
          <tr>
            <td style={{
    fontWeight: '600',
    paddingRight: '32px',
    paddingBottom: '14px',
    whiteSpace: 'nowrap',
    verticalAlign: 'middle'
  }}>Connection Inputs</td>
            <td style={{
    paddingBottom: '14px',
    verticalAlign: 'middle'
  }}>{connectionInputs}</td>
          </tr>
          <tr>
            <td style={{
    fontWeight: '600',
    paddingRight: '32px',
    whiteSpace: 'nowrap',
    verticalAlign: 'middle'
  }}>Connection Outputs</td>
            <td style={{
    verticalAlign: 'middle'
  }}>{connectionOutputs}</td>
          </tr>
        </tbody>
      </table>
    </div>;
};

<ComponentMetadata warehouses={["Snowflake", "Amazon Redshift", "Google BigQuery"]} unsupportedWarehouses={["Databricks"]} componentType="Transformation" connectionInputs="One" connectionOutputs="Unlimited" />

The **Transpose Columns** transformation component rotates a table by transforming columns from the input dataset into rows in the output data. This reshapes data by outputting multiple rows for each individual input row. Each set of input columns is mapped to an output column. The output rows are labelled to determine which column the value originated from.

This component effectively performs the reverse of a pivot operation on the data. Consider the [Unpivot](/docs/components/unpivot) component for an alternative way of obtaining similar results.

<Note>
  There is no fixed limit on the number of columns you can transpose. The maximum depends on the structure of your source table and the query complexity limits of your data warehouse.
</Note>

### Use case

This component is useful when you have "wide" data (many columns) that you want to make "long" or normalized to help with analytics, modeling, and reporting. Some typical uses of this are:

* Unpivoting time-based data to allow time-series analysis. For example, convert a table with one column per year into a table with one row per year.
* Converting multiple response columns from a survey into a normalized format for easier filtering and aggregation.

***

## Properties

<Tabs>
  <Tab title="Snowflake">
    <ResponseField name="Name" type="string" required>
      A human-readable name for the component.
    </ResponseField>

    {/* <!-- param-start:[ordinaryColumns] | warehouses: [snowflake] --> */}

    <ResponseField name="Ordinary columns" type="dual listbox" required>
      Choose the ordinary columns, those that are not going to be transposed but are still required in the output. These are effectively a set of grouping columns that are passed to the output unchanged.

      To use grid variables, toggle **Use Grid Variable** on at the bottom of the dialog. For more information, read [Grid variables](/docs/guides/grid-variables).
    </ResponseField>

    {/* <!-- param-start:[rowLabelName] | warehouses: [snowflake] --> */}

    <ResponseField name="Row label name" type="string" required>
      Provide the name of a new column here. It will contain constants you enter into the **Column to Row Mapping** property, which identifies the original column that the new row originated from.
    </ResponseField>

    {/* <!-- param-start:[outputColumns] | warehouses: [snowflake] --> */}

    <ResponseField name="Output columns" type="column editor" required>
      * **Name:** A new column name to hold the output of multiple input columns.
      * **Type:** Specify the data type for the column. Should be compatible with all input columns that will be mapped into this column. This is used to validate that the input columns all conform to the type of the output column. Choose from the following data types:

        * [VARCHAR](https://docs.snowflake.com/en/sql-reference/data-types-text#varchar): This type is suitable for numbers and letters. A varchar or Variable Character field is a set of character data of indeterminate length.
        * [NUMBER](https://docs.snowflake.com/en/sql-reference/data-types-numeric#number): This type is suitable for numeric types, with or without decimals.
        * [FLOAT](https://docs.snowflake.com/en/sql-reference/data-types-numeric#float-float4-float8): This type of values are approximate numeric values with fractional components.
        * [BOOLEAN](https://docs.snowflake.com/en/sql-reference/data-types-logical#boolean): This type is suitable for data that is either "true" or "false".
        * [DATE](https://docs.snowflake.com/en/sql-reference/data-types-datetime#date): This type is suitable for dates without times.
        * [TIMESTAMP](https://docs.snowflake.com/en/sql-reference/data-types-datetime#timestamp): This type is a timestamp left unformatted (exists as Unix/Epoch Time).
        * [TIME](https://docs.snowflake.com/en/sql-reference/data-types-datetime#time): This type is suitable for time, independent of a specific date and timezone.
        * [VARIANT](https://docs.snowflake.com/en/sql-reference/data-types-semistructured#variant): Variant is a tagged universal type that can hold up to 16 MB of any data type supported by Snowflake.

        Click the **Text mode** toggle at the bottom of the dialog to open a multi-line editor that lets you add items in a single block. For more information, read [Text mode](/docs/guides/components-overview#text-mode).

        To use grid variables, toggle **Use Grid Variable** on at the bottom of the dialog. For more information, read [Grid variables](/docs/guides/grid-variables).
    </ResponseField>

    {/* <!-- param-start:[columnToRowMapping] | warehouses: [snowflake] --> */}

    <ResponseField name="Column to row mapping" type="column editor" required>
      * **Row Label Name:** This editor column will actually appear as the label provided in Row Label Name. Enter an identifier to specify what the rows represent.
      * **Output Column-1:** Each defined output column will appear as a column in this mapping. Add a row to this grid for each input column you want to map into an output column.
      * **Output Column-n:** As above, if you are mapping multiple sets of input columns. When you map data into multiple output columns, there should be a set of similar input columns for each output column. For example, you may have a set of input columns for each quarterly revenue amount, and another set of input columns for quarterly profits.

      Click the **Text mode** toggle at the bottom of the dialog to open a multi-line editor that lets you add items in a single block. For more information, read [Text mode](/docs/guides/components-overview#text-mode).

      To use grid variables, toggle **Use Grid Variable** on at the bottom of the dialog. For more information, read [Grid variables](/docs/guides/grid-variables).
    </ResponseField>
  </Tab>

  <Tab title="Amazon Redshift">
    <ResponseField name="Name" type="string" required>
      A human-readable name for the component.
    </ResponseField>

    {/* <!-- param-start:[ordinaryColumns] | warehouses: [redshift] --> */}

    <ResponseField name="Ordinary columns" type="dual listbox" required>
      Choose the ordinary columns, those that are not going to be transposed but are still required in the output. These are effectively a set of grouping columns that are passed to the output unchanged.

      To use grid variables, toggle **Use Grid Variable** on at the bottom of the dialog. For more information, read [Grid variables](/docs/guides/grid-variables).
    </ResponseField>

    {/* <!-- param-start:[rowLabelName] | warehouses: [redshift] --> */}

    <ResponseField name="Row label name" type="string" required>
      Provide the name of a new column here. It will contain constants you enter into the **Column to Row Mapping** property, which identifies the original column that the new row originated from.
    </ResponseField>

    {/* <!-- param-start:[outputColumns] | warehouses: [redshift] --> */}

    <ResponseField name="Output columns" type="column editor" required>
      * **Name:** A new column name to hold the output of multiple input columns.
      * **Type:** Specify the data type for the column. Should be compatible with all input columns that will be mapped into this column. This is used to validate that the input columns all conform to the type of the output column. Choose from the following data types:
        * [TEXT](https://docs.aws.amazon.com/redshift/latest/dg/r_Character_types.html#r_Character_types-text-and-bpchar-types): A string that can hold any kind of data, subject to a maximum size.
        * [INTEGER](https://docs.aws.amazon.com/redshift/latest/dg/r_Numeric_types201.html#r_Numeric_types201-integer-types): An integer data type is suitable for whole numbers (no decimals).
        * [NUMERIC](https://docs.aws.amazon.com/redshift/latest/dg/r_Numeric_types201.html#r_Numeric_types201-decimal-or-numeric-type): The numeric data type accepts numbers, with or without decimals.
        * [REAL](https://docs.aws.amazon.com/redshift/latest/dg/r_Numeric_types201.html): This type is suitable for data of a single precision floating point number.
        * [DOUBLE PRECISION](https://docs.aws.amazon.com/redshift/latest/dg/r_Numeric_types201.html): This type is suitable for data of a double precision floating point number.
        * [BOOLEAN](https://docs.aws.amazon.com/redshift/latest/dg/r_Boolean_type.html): Data with a Boolean data type can be either "true" or "false".
        * [DATE](https://docs.aws.amazon.com/redshift/latest/dg/r_Datetime_types.html#r_Datetime_types-date): This type is suitable for dates without times.
        * [DATETIME](https://docs.aws.amazon.com/redshift/latest/dg/r_Datetime_types.html): This type is suitable for dates, times, or timestamps (both date and time).
        * [SUPER](https://docs.aws.amazon.com/redshift/latest/dg/r_SUPER_type.html): Uses the SUPER data type to store semi-structured data or documents as values.

      Click the **Text mode** toggle at the bottom of the dialog to open a multi-line editor that lets you add items in a single block. For more information, read [Text mode](/docs/guides/components-overview#text-mode).

      To use grid variables, toggle **Use Grid Variable** on at the bottom of the dialog. For more information, read [Grid variables](/docs/guides/grid-variables).
    </ResponseField>

    {/* <!-- param-start:[columnToRowMapping] | warehouses: [redshift] --> */}

    <ResponseField name="Column to row mapping" type="column editor" required>
      * **Row Label Name:** This editor column will actually appear as the label provided in Row Label Name. Enter an identifier to specify what the rows represent.
      * **Output Column-1:** Each defined output column will appear as a column in this mapping. Add a row to this grid for each input column you want to map into an output column.
      * **Output Column-n:** As above, if you are mapping multiple sets of input columns. When you map data into multiple output columns, there should be a set of similar input columns for each output column. For example, you may have a set of input columns for each quarterly revenue amount, and another set of input columns for quarterly profits.

      Click the **Text mode** toggle at the bottom of the dialog to open a multi-line editor that lets you add items in a single block. For more information, read [Text mode](/docs/guides/components-overview#text-mode).

      To use grid variables, toggle **Use Grid Variable** on at the bottom of the dialog. For more information, read [Grid variables](/docs/guides/grid-variables).
    </ResponseField>
  </Tab>

  <Tab title="Google BigQuery">
    <ResponseField name="Name" type="string" required>
      A human-readable name for the component.
    </ResponseField>

    {/* <!-- param-start:[ordinaryColumns] | warehouses: [bigquery] --> */}

    <ResponseField name="Ordinary columns" type="dual listbox" required>
      Choose the ordinary columns, those that are not going to be transposed but are still required in the output. These are effectively a set of grouping columns that are passed to the output unchanged.

      To use grid variables, toggle **Use Grid Variable** on at the bottom of the dialog. For more information, read [Grid variables](/docs/guides/grid-variables).
    </ResponseField>

    {/* <!-- param-start:[rowLabelName] | warehouses: [bigquery] --> */}

    <ResponseField name="Row label name" type="string" required>
      Provide the name of a new column here. It will contain constants you enter into the **Column to Row Mapping** property, which identifies the original column that the new row originated from.
    </ResponseField>

    {/* <!-- param-start:[outputColumns] | warehouses: [bigquery] --> */}

    <ResponseField name="Output columns" type="column editor" required>
      * **Name:** A new column name to hold the output of multiple input columns.
      * **Type:** Specify the data type for the column. Should be compatible with all input columns that will be mapped into this column. This is used to validate that the input columns all conform to the type of the output column. Choose from the following data types:

        * [STRING](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#string_type)
        * [INT64](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#int64_type)
        * [FLOAT64](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#float64_type)
        * [NUMERIC](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#numeric_type)
        * [BIGNUMERIC](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#bignumeric_type)
        * [BOOL](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#bool_type)
        * [BYTES](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#bytes_type)
        * [DATE](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#date_type)
        * [DATETIME](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#datetime_type)
        * [TIME](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#time_type)
        * [TIMESTAMP](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#timestamp_type)
        * [INTERVAL](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/data-types#interval_type)

        Click the **Text mode** toggle at the bottom of the dialog to open a multi-line editor that lets you add items in a single block. For more information, read [Text mode](/docs/guides/components-overview#text-mode).

        To use grid variables, toggle **Use Grid Variable** on at the bottom of the dialog. For more information, read [Grid variables](/docs/guides/grid-variables).
    </ResponseField>

    {/* <!-- param-start:[columnToRowMapping] | warehouses: [bigquery] --> */}

    <ResponseField name="Column to row mapping" type="column editor" required>
      * **Row Label Name:** This editor column will actually appear as the label provided in Row Label Name. Enter an identifier to specify what the rows represent.
      * **Output Column-1:** Each defined output column will appear as a column in this mapping. Add a row to this grid for each input column you want to map into an output column.
      * **Output Column-n:** As above, if you are mapping multiple sets of input columns. When you map data into multiple output columns, there should be a set of similar input columns for each output column. For example, you may have a set of input columns for each quarterly revenue amount, and another set of input columns for quarterly profits.

      Click the **Text mode** toggle at the bottom of the dialog to open a multi-line editor that lets you add items in a single block. For more information, read [Text mode](/docs/guides/components-overview#text-mode).

      To use grid variables, toggle **Use Grid Variable** on at the bottom of the dialog. For more information, read [Grid variables](/docs/guides/grid-variables).
    </ResponseField>
  </Tab>
</Tabs>

## Example

We have a table of products and yearly sales information. However, the format doesn't allow us to easily do analysis by year:

```
Input Data

+-------------+------------+------------+
| product_id  | sales_2023 | sales_2024 |
+-------------+------------+------------+
| P123        | 1000.00    | 1500.00    |
| P124        | 2500.00    | 3000.00    |
| P125        | 1800.00    | 2200.00    |
| P126        | 3500.00    | 4000.00    |
+-------------+------------+------------+
```

We want to transpose the data into a form that has a single "year" column, which will allow us to sort and filter on that column. Our output table should look like this:

```
Output data

+------------+------+---------+
| product_id | year | sales   |
+------------+------+---------+
| P123       | 2023 | 1000.00 |
| P124       | 2023 | 2500.00 |
| P125       | 2023 | 1800.00 |
| P126       | 2023 | 3500.00 |
| P123       | 2024 | 1500.00 |
| P124       | 2024 | 3000.00 |
| P125       | 2024 | 2200.00 |
| P126       | 2024 | 4000.00 |
+------------+------+---------+
```

To achieve this transformation, we connect the input table to a Transpose Columns component, which we will configure as follows:

* **Ordinary Columns:** product\_id
* **Row Label Name:** year
* **Output Columns:**
  * **Name:** sales
  * **Type:** NUMBER
* **Columns To Row Mapping:**
  * **year:** 2023 **sales:** sales\_2023
  * **year:** 2024 **sales:** sales\_2024

The **Columns To Row Mapping** property is the key to this transformation, as it tells us that for each `product_id` in the input, data from the original `sales_2023` column goes into an output row with "2023" in the `year` column, while data from the original `sales_2024` column goes into a separate output row with "2024" in the `year` column.
