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

# Describe a Snowflake table

> Get the columns of a table, with how well the table is clustered on each.

For each request, SELECT runs the SELECT stored procedure that is installed
in your Snowflake account. It runs one query for each column that is not
semi-structured, and one for the clustering key, so the cost and the time
increase with the number of columns. The queries need a running warehouse
and use credits in your account. SELECT does not keep the result, so each
request runs all the queries again.

When the stored procedure is not set up for the account, the response is a
`409` with the code `describe_procedure_unavailable`. The `detail` member
tells what to set up.



## OpenAPI

````yaml https://api.select.dev/v2/openapi.json post /snowflake-accounts/{snowflake_account_id}/actions/describe-table
openapi: 3.1.0
info:
  title: SELECT API (v2)
  version: 0.1.0
servers:
  - url: https://api.select.dev/v2
    description: SELECT API v2
security: []
tags:
  - name: metrics
    description: >-
      Query cost and usage data across Snowflake, BigQuery, Databricks and
      Tableau. Each route is `POST /v2/metrics/<model>/query` for one semantic
      model. Every route takes the same body shape and returns the same response
      shape. Each route page gives guidance on when to use the route, and worked
      examples.


      ## Body shape


      | Field | Meaning |

      | --- | --- |

      | `measures` | Aggregates to compute, for example `sum_spend`. |

      | `dimensions` | Fields to group by. Each one is returned on every row. |

      | `filter_expression` | An `and`/`or` tree of filters on dimensions,
      applied before aggregation. |

      | `measure_filters` | Filters on measures, applied after aggregation. |

      | `sort` | The order of the rows: `[{"field": "sum_spend", "direction":
      "desc"}]`. |

      | `limit` | The maximum number of rows. Results are not paginated: `limit`
      cuts the result short, and there is no next page. Omit `limit` to get all
      rows. |

      | `aggregate` | Set `false` to list the rows with no grouping. See
      "Listing rows". |


      v2 accepts only `filter_expression`. The body refuses the legacy `filters`
      list.


      ## Filter on dates


      Filter on the `day` field. Use two filters (both bounds are inclusive):


      ```json

      {"operator": "and", "filters": [
        {"field": "day", "operator": ">=", "value": "2026-08-01"},
        {"field": "day", "operator": "<=", "value": "2026-08-31"}], "limit": 1000}
      ```


      Or use one relative filter: `{"field": "day", "operator": "in range",
      "value": "30D"}`. The values are `{N}D` and `{N}M` (the last N days or
      months, today included), `WTD`, `MTD`, `QTD`, `YTD`, and `LMTD` (the whole
      previous calendar month).


      - Do not filter on `hour`, `week`, `month` or `quarter` to bound a range.
      Filter on `day`, and use the coarser fields as dimensions.

      - A timestamp such as `start_time <= "2026-08-31"` compares to midnight
      and drops most of that day. Use `day`, or `start_time < "2026-09-01"`.

      - A snapshot route (for example `snowflake-storage-summary`) describes the
      current state, and a `day` filter does not bound its size and cost fields.
      On routes that join the snapshot to activity, `day` bounds only the
      activity fields. Each route page says which fields these are.


      ## Which measure is cost


      - `sum_spend` (or `spend`, or `cost` on some routes) is the dollar cost in
      the filtered period. Use it for "how much did we spend".

      - `*_annualized` measures extend the spend of the filtered period to a
      year: a `7D` range gives that week's spend times 365 / 7. They are
      projections, not spend.

      - On snapshot routes, `annual_cost`, `*_monthly_cost` and `*_annual_cost`
      are the current rate extended to a month or a year. A date range does not
      bound them.

      - Do not present any of these run-rates as spend in a period.

      - Databricks routes also give DBUs (for example `sum_task_usage`). DBUs
      are not dollars.


      The `spend` route is the consolidated cost of every platform. Use it for
      totals, trends and breakdowns by service. Use a platform route to explain
      what inside the platform caused the cost.


      ## Text values are case-sensitive


      Filter values must match the stored case. A value in the wrong case
      matches no rows, with no error. For example:


      - On `spend`, `connection_type` is `Snowflake`, `Bigquery` or
      `Databricks`, and `"snowflake"` matches nothing.

      - On `search`, `data-freshness` and `workload-metadata-suggestions`,
      `connection_type` is lowercase: `snowflake`, `bigquery`, `databricks`.

      - On `snowflake-workloads`, most `resource_type` values are lowercase keys
      (`query_pattern`, `dbt`), but the AI types are title case (`Cortex
      Analyst`).


      ## Usage groups


      A usage group set divides cost into named groups, such as departments or
      teams. To group by the groups of one set, name the set in `path`:


      ```json

      {"dimensions": [{"field": "usage_group", "path": ["Department"]}],
      "limit": 1000}

      ```


      `path[0]` is the name of the set, not its ID. A plain `"usage_group"`
      dimension groups by every set at once. The same `{"field": ..., "path":
      [...]}` form reads keys of other semi-structured fields, for example
      workload metadata.


      ## Period over period


      Some routes publish `<measure>_previous_period`, `change_<measure>` and
      `percent_change_<measure>`. These measures need one bounded date range on
      `day`, at the top level of `filter_expression`:


      - Use two bounds on `day`, or one `in range` filter. Do not mix the two
      forms.

      - Do not nest the date filter in a sub-expression, and do not bound the
      range with `month` or `quarter`.

      - The previous period is the same number of days, just before the range.
      For `QTD` on 2026-09-28 (2026-07-01 to 2026-09-28, 90 days), the previous
      period is 2026-04-02 to 2026-06-30, not the previous calendar quarter.


      ## Listing rows


      Set `"aggregate": false` and name only `dimensions` to get the rows as
      they are, for example the individual queries that ran longer than ten
      minutes. If the body also names `measures` or `measure_filters`, the route
      aggregates, with no error. Always set a `limit` on a listing.


      ## Default scoping filters


      Some tables hold more than one kind of row, and the SELECT app filters to
      one kind by default. Each route page names these filters. For example:


      - `snowflake-query-patterns`: `{"field": "resource_type", "operator":
      "in", "values": ["query_pattern"]}`. `bigquery-query-patterns` filters
      `workload_type` to `bigquery_query_pattern`, and
      `databricks-query-patterns` filters `resource_type` to
      `databricks_query_pattern`.

      - `snowflake-dbt`: `{"field": "dbt_node_resource_type", "operator": "=",
      "value": "model"}`. Without it, tests, seeds and snapshots rank with
      models. The same filter applies to `bigquery-dbt-queries` and
      `databricks-dbt-queries`.


      ## Teams


      Send `X-Team-Id` to evaluate a query as a team you belong to. The rows are
      then limited to what the team's roles can reach.


      ## Which route answers which question


      | Question | Route |

      | --- | --- |

      | Total spend, spend trend, spend by platform, service or usage group |
      `spend` |

      | Most expensive Snowflake warehouses | `snowflake-workloads` (or
      `snowflake-warehouses` for metering spend) |

      | Warehouse utilization, idle spend, cluster usage |
      `snowflake-warehouses`, `snowflake-warehouse-clusters` |

      | Query latency, spillage and bytes scanned on a warehouse |
      `snowflake-warehouse-query-performance` |

      | Most expensive recurring queries | `snowflake-query-patterns` |

      | Individual queries | `snowflake-queries` |

      | Cost of dbt models, and of dbt runs | `snowflake-dbt`,
      `snowflake-dbt-invocations` |

      | Cost of tasks, stored procedures, dynamic tables | `snowflake-tasks`,
      `snowflake-stored-procedures`, `snowflake-dynamic-tables` |

      | Cost of BI tools (Looker, Mode, Hex, Sigma, Periscope, Tableau) |
      `snowflake-looker`, `snowflake-mode`, `snowflake-hex`, `snowflake-sigma`,
      `snowflake-periscope`, `tableau-queries` |

      | Cost of Fivetran, and of workloads defined by query tags |
      `snowflake-fivetran`, `snowflake-custom-workloads` |

      | Serverless, automatic clustering and Snowpipe cost |
      `snowflake-serverless`, `snowflake-automatic-clustering`,
      `snowflake-snowpipe` |

      | Storage cost in a period | `snowflake-storage`, `bigquery-storage-spend`
      |

      | Largest or unused tables now | `snowflake-storage-summary`,
      `bigquery-storage-summary` |

      | Which workloads read or write a table | `lineage-workloads`,
      `lineage-tables`, `lineage-edges` |

      | BigQuery cost by project, job or query pattern | `bigquery-projects`,
      `bigquery-jobs`, `bigquery-query-patterns` |

      | BigQuery reservations and commitments | `bigquery-reservation-timeline`,
      `bigquery-commitments`, `bigquery-commitment-scopes` |

      | Databricks cost by job, query, SQL warehouse or cluster |
      `databricks-jobs`, `databricks-queries`, `databricks-sql-warehouses`,
      `databricks-clusters` |

      | Savings from SELECT actions | `action-realized-savings` |

      | How current the data is | `data-freshness` |
paths:
  /snowflake-accounts/{snowflake_account_id}/actions/describe-table:
    post:
      tags:
        - snowflake-accounts
      summary: Describe a Snowflake table
      description: >-
        Get the columns of a table, with how well the table is clustered on
        each.


        For each request, SELECT runs the SELECT stored procedure that is
        installed

        in your Snowflake account. It runs one query for each column that is not

        semi-structured, and one for the clustering key, so the cost and the
        time

        increase with the number of columns. The queries need a running
        warehouse

        and use credits in your account. SELECT does not keep the result, so
        each

        request runs all the queries again.


        When the stored procedure is not set up for the account, the response is
        a

        `409` with the code `describe_procedure_unavailable`. The `detail`
        member

        tells what to set up.
      operationId: >-
        describe_snowflake_table_route_snowflake_accounts__snowflake_account_id__actions_describe_table_post
      parameters:
        - name: snowflake_account_id
          in: path
          required: true
          schema:
            type: string
            title: Snowflake Account Id
        - name: x-tenant-id
          in: header
          required: true
          schema:
            type: string
            description: The organization ID the request is scoped to.
            title: X-Tenant-Id
          description: The organization ID the request is scoped to.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SnowflakeTableDescribeRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SnowflakeTableDescriptionV2'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '405':
          $ref: '#/components/responses/MethodNotAllowed'
        '408':
          $ref: '#/components/responses/RequestTimeout'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
      security:
        - HTTPBearer: []
components:
  schemas:
    SnowflakeTableDescribeRequest:
      properties:
        database_name:
          type: string
          minLength: 1
          title: Database Name
          description: The name of the database. The match is exact and case-sensitive.
        schema_name:
          type: string
          minLength: 1
          title: Schema Name
          description: The name of the schema. The match is exact and case-sensitive.
        table_name:
          type: string
          minLength: 1
          title: Table Name
          description: The name of the table. The match is exact and case-sensitive.
      additionalProperties: false
      type: object
      required:
        - database_name
        - schema_name
        - table_name
      title: SnowflakeTableDescribeRequest
      description: The table to describe.
    SnowflakeTableDescriptionV2:
      properties:
        columns:
          items:
            $ref: '#/components/schemas/SnowflakeTableColumnV2'
          type: array
          title: Columns
          description: The columns of the table.
        clustering_key:
          anyOf:
            - $ref: '#/components/schemas/SnowflakeClusteringInformationV2'
            - type: 'null'
          description: >-
            How well the table is clustered on its clustering key. `null` when
            the table has no clustering key.
        version:
          type: string
          title: Version
          description: The version of the SELECT stored procedure that described the table.
      type: object
      required:
        - columns
        - clustering_key
        - version
      title: SnowflakeTableDescription
      description: The columns of a Snowflake table, with their clustering information.
    SnowflakeTableColumnV2:
      properties:
        name:
          type: string
          title: Name
          description: The name of the column.
        type:
          type: string
          title: Type
          description: The Snowflake data type, for example `NUMBER(38,0)`.
        kind:
          type: string
          title: Kind
          description: The Snowflake kind of the column, for example `COLUMN`.
        is_null:
          type: boolean
          title: Is Null
          description: Whether the column accepts null values.
        default:
          anyOf:
            - type: string
            - type: 'null'
          title: Default
          description: The default value of the column.
          x-doit-confidentiality: customer-data
        primary_key:
          type: string
          title: Primary Key
          description: '`Y` when the column is part of the primary key, else `N`.'
        unique_key:
          type: string
          title: Unique Key
          description: '`Y` when the column is part of a unique key, else `N`.'
        check:
          anyOf:
            - type: string
            - type: 'null'
          title: Check
          description: The check constraint of the column.
          x-doit-confidentiality: customer-data
        expression:
          anyOf:
            - type: string
            - type: 'null'
          title: Expression
          description: The expression of a virtual column.
          x-doit-confidentiality: customer-data
        comment:
          anyOf:
            - type: string
            - type: 'null'
          title: Comment
          description: The comment of the column.
          x-doit-confidentiality: customer-data
        policy_name:
          anyOf:
            - type: string
            - type: 'null'
          title: Policy Name
          description: The masking policy of the column.
        privacy_domain:
          anyOf:
            - type: string
            - type: 'null'
          title: Privacy Domain
          description: The privacy domain of the column.
        clustering_information:
          anyOf:
            - $ref: '#/components/schemas/SnowflakeClusteringInformationV2'
            - type: 'null'
          description: >-
            How well the table is clustered on this column. `null` for a
            semi-structured column, or when Snowflake does not report it.
      type: object
      required:
        - name
        - type
        - kind
        - is_null
        - default
        - primary_key
        - unique_key
        - check
        - expression
        - comment
        - policy_name
        - privacy_domain
      title: SnowflakeTableColumn
      description: One column of a Snowflake table.
    SnowflakeClusteringInformationV2:
      properties:
        average_depth:
          type: number
          title: Average Depth
          description: >-
            The average number of micro-partitions that overlap for a value of
            the clustering columns.
        average_overlaps:
          type: number
          title: Average Overlaps
          description: >-
            The average number of other micro-partitions that overlap each
            micro-partition.
        cluster_by_keys:
          type: string
          title: Cluster By Keys
          description: The columns that the clustering information is for.
        clustering_errors:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Clustering Errors
          description: The errors that Snowflake reports for automatic clustering.
        total_constant_partition_count:
          type: integer
          title: Total Constant Partition Count
          description: >-
            The number of micro-partitions in which the clustering columns have
            one value only.
        total_partition_count:
          type: integer
          title: Total Partition Count
          description: The number of micro-partitions of the table.
        partition_depth_histogram:
          anyOf:
            - additionalProperties:
                type: number
              type: object
            - type: 'null'
          title: Partition Depth Histogram
          description: >-
            The number of micro-partitions for each overlap depth. `null` when
            Snowflake does not report it.
        version:
          anyOf:
            - type: string
            - type: 'null'
          title: Version
          description: >-
            The kind of clustering information, for example `OPTIMA`. `null` for
            the standard kind.
      type: object
      required:
        - average_depth
        - average_overlaps
        - cluster_by_keys
        - clustering_errors
        - total_constant_partition_count
        - total_partition_count
      title: SnowflakeClusteringInformation
      description: >-
        How well the micro-partitions of a table are clustered on a set of
        columns.
    ProblemDetail:
      additionalProperties: true
      description: >-
        RFC 9457-style error payload, served as ``application/problem+json``.


        ``code`` is the stable, machine-readable identifier — consumers branch
        on it,

        never on ``title``. ``type`` stays ``about:blank``: we keep no per-error

        documentation pages. There is no ``instance``/request-id member (we
        don't run

        access logs). See the flat error-code catalogue in §4 of the standards
        doc.
      properties:
        type:
          default: about:blank
          title: Type
          type: string
        title:
          type: string
          title: Title
        status:
          title: Status
          type: integer
        detail:
          title: Detail
          type: string
        code:
          title: Code
          type: string
        retryable:
          title: Retryable
          type: boolean
        details:
          anyOf:
            - items:
                additionalProperties: true
                type: object
              type: array
            - type: 'null'
          default: null
          title: Details
      required:
        - title
        - status
        - detail
        - code
        - retryable
      title: ProblemDetail
      type: object
  responses:
    BadRequest:
      description: Bad request
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
    Unauthorized:
      description: Unauthorized
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
      headers:
        WWW-Authenticate:
          description: Authentication challenge for the requested resource.
          required: true
          schema:
            type: string
    Forbidden:
      description: Forbidden
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
    NotFound:
      description: Not found
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
    MethodNotAllowed:
      description: Method not allowed
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
      headers:
        Allow:
          description: HTTP methods supported by the requested resource.
          required: true
          schema:
            type: string
    RequestTimeout:
      description: Request Timeout
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
    Conflict:
      description: Conflict
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
    ValidationFailed:
      description: Validation failed
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
    RateLimited:
      description: Rate limited
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
      headers:
        Retry-After:
          description: Number of seconds to wait before retrying the request.
          required: true
          schema:
            type: integer
            minimum: 0
    InternalError:
      description: Internal error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
    ServiceUnavailable:
      description: Service unavailable
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
      headers:
        Retry-After:
          description: Number of seconds to wait before retrying the request.
          required: true
          schema:
            type: integer
            minimum: 0
  securitySchemes:
    HTTPBearer:
      type: http
      description: Organization API key (sl_…).
      scheme: bearer

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.