# Views

Views reference exactly one table in the database. In Zenlytic, they are organized into [topics](/legacy/topic.md) for usage that define how they join together.

Views, like all files in Zenlytic, are YAML text files.

## Properties

`type`: (Required) The type of the file. For these view files is should always be `view`.

`name`: (Required) The name of the view. If you reference this view elsewhere this is the name you will use. Like all names, it follows [Zenlytic naming conventions](/data-modeling/data_modeling.md#naming-conventions)

`model_name`: (Required) The name of the [model](/data-modeling/model.md) (e.g. database connection) the view references.

`label`: The label of the view is what shows up to the end users of your data model. If not specified it defaults to the name of the view.

`description`: The description of the view. This can help business users understand what the view represents and how it is created. This is also sent to Zoë (Zenlytic's AI Analyst) to give her context on how to use different views in your data model. Use this to provide Zoë view or table-level context.

`zoe_description`: The description of the view shown to Zoë. If not set, Zoë uses `description` instead. If set, this replaces `description` for Zoë only. End users will still see `description` in the UI. Use this to provide context to Zoë on how to use the view correctly.

{% hint style="info" %}
**View-level `description` and `zoe_description` are capped at 10,000 characters each** — plenty of room for join-path guidance, data caveats, and edge cases. Use `description` for user-facing documentation and `zoe_description` for agent-only instructions like which joins to prefer or pitfalls to avoid. See [Context Surfaces](/core-concepts/context-surfaces.md) for when to use views vs. fields vs. the system prompt vs. skills.
{% endhint %}

`sql_table_name`: This is the table name in the database that the view references. For example, `prod.customers` would be a valid `sql_table_name`.

`derived_table`: This is a property that you can use to define transformed tables using a SQL statement. This SQL statement is run and is considered to be the "base" of the view. Note, we generally prefer using [dbt](https://getdbt.com) over derived tables for better testing and maintainability. This property has a nested property `sql` inside of the `derived_table` property that you use to define the SQL statement.

{% code overflow="wrap" %}

```yaml
...
name: my_view
derived_table: 
  sql: "select *, row_number() over (partition by customer_id order by order_date) as order_number from myschema.mytable"
...
```

{% endcode %}

Note: The filters in `always_filter` *will not* be applied if you are using this property to define the data for the view to sit on top of.

You can also reference any [referenceable attributes](/data-modeling/referenceable_attributes.md) and drop them into the derived SQL statement. For example, in this case we are dynamically applying a filter to the SQL query based on the user's user attribute for 'owned\_region'

```yaml

name: my_view
derived_table: 
  sql: >
    select 
      * 
    from myschema.mytable
    where '{{ user_attributes['owned_region'] }}' = mytable.region

```

`default_date`: This is the default date [dimension group](/data-modeling/dimension_group.md) without a time frame chosen for it. For example, if your dimension group is named `order` you would use the value `order` here, not `order_month` or `order_week` like you would reference elsewhere.

{% hint style="info" %}
**Set `default_date` on every view that has time-series measures.** It is the single most impactful structural property for temporal queries — it tells Zoë which date dimension to use for questions like "revenue this quarter" against this view. Prefer setting `default_date` on the view over setting `canon_date` on individual measures; `canon_date` should only be used when a specific measure genuinely needs a different date than the view default.
{% endhint %}

`sets`: This is a list of [sets](/data-modeling/set.md) that are defined in this view. Example syntax of the definition is below.

```yaml
  - name: set_name
    fields: [field_or_set, field_or_set]
```

`always_filter`: This is an optional list of filters which use the usual [field filter selection syntax](/data-modeling/field_filter.md) and will *always* be applied to the query. These filters are applied to the entire query, not just a metric or dimension, and if it is not possible to reference or join in the field needed for the filter it will result in an error.

Note: This set of filters *will not* be applied if you are using a derived table mentioned above instead of `sql_table_name`.

### Example below:

Here are two filters that will be applied to *all* queries that reference this view. One field `context_os` is present in the view, and does not need to specify its view name. The other field `is_churned` is *not* present in this view and must specify its view name. It will be joined in dynamically whenever this view is referenced to apply the filter.

```yaml
always_filter:
- field: customers.is_churned
  value: FALSE
- field: context_os
  value: -NULL
```

`access_filters`: This is an optional list of [access filters](/data-modeling/access_grants.md#access-filters) to apply to the view when it is queried.

Access filters can be used to apply row-level security against views. The following example shows how to make a specified column only visible to workspace members with a user attribute value:

```yaml
access_filters:
  - field: orders.product
    user_attribute: 'products'
```

`required_access_grants`: This is a list of [access grant](/data-modeling/access_grants.md#access-grants) names that are required to access this view. If you list multiple grants, they must all pass for the user to access this view. A missing user attribute on a grant is non-blocking for that grant, because the grant is not triggered. Note, these access grants will *always* be applied for this view in any join sequence.

`identifiers`: This is a list of [fields](/data-modeling/field.md) with additional information defining what kind of key (primary, foreign) they are to the table the view references.

Identifiers can be used to create a `join_as` view, which will allow a table to join into a topic more than once on different keys. More information is in the [joins](/legacy/join.md) section.

`fields`: This is a list of [fields](https://github.com/Zenlytic/zenlytic-docs/blob/main/5_data_modeling/9_field.md). Each field must have all required parameters included.

## Joins

Joins are defined in [topics](/legacy/topic.md).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.zenlytic.com/data-modeling/view.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
