> For the complete documentation index, see [llms.txt](https://docs.opendatadiscovery.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.opendatadiscovery.org/features/data-modelling/query-examples.md).

# Query Examples

**Query Examples** are operator-curated query snippets — typically SQL, but anything that reads as a "how the team uses this dataset" example — attached to one or more data entities and optionally linked to glossary terms. They turn the catalog from "what we have" into "what we have *and* how to use it", without forcing readers to dig into a wiki or ping the team that owns the data.

Query Examples is the first sub-surface of the [Data Modelling](/features/data-modelling.md) section.

## What you can do

* **Author and edit** snippets with a name, description, and the query body. The description doubles as a "prompt"-style explanation of intent.
* **Link a snippet to one or more data entities** (tables, views, files) so it shows up on the entity's detail page as one of the canonical examples.
* **Link a snippet to glossary terms** so terminology + canonical usage stay close to each other.
* **Search the catalog of snippets** with a dedicated faceted search that supports filters, the same shape as the main catalog search.
* **Get search suggestions** as you type — the top five matching snippet titles for a query string.

## UI walkthrough

Open **Data Modelling → Query Examples** from the top-level navigation (`/data-modelling/query-examples`). The list view shows every snippet the user is allowed to read, with a search box and an "Add query example" button. The button is gated by the `QUERY_EXAMPLE_CREATE` permission — users without it see the list but no create entry-point.

![Query Examples list page — each row carries the snippet's number, definition, query body preview, linked data entities (ORDERS, CUSTOMER, LINEITEM), and any linked glossary terms (2NF). The left-rail switches between Query Examples and Relationships, the two Data Modelling sub-surfaces.](/files/Gxw6Wt7fG12YwN5yMOrd)

* **List page** (`/data-modelling/query-examples`) — all snippets, with search, total count, and the create button.
* **Details / edit page** (`/data-modelling/query-examples/{id}`) — the snippet's full body, its description, and the linked data entities and terms. Edit and delete actions are gated by `QUERY_EXAMPLE_UPDATE` and `QUERY_EXAMPLE_DELETE` respectively.
* **On a dataset's detail page** — Query Examples linked to that dataset surface in the dataset's "Query Examples" tab; operators with `QUERY_EXAMPLE_DATASET_CREATE` can attach existing snippets, and `QUERY_EXAMPLE_DATASET_DELETE` users can detach.
* **On a term's detail page** — same pattern, gated by `QUERY_EXAMPLE_TERM_CREATE` and `QUERY_EXAMPLE_TERM_DELETE`.

## Permissions (RBAC)

Seven permissions on the Query Example surface, all configurable on roles via the standard authorization model (see [Authorization → Roles](/configuration-and-deployment/enable-security/authorization/roles.md)):

| Permission                     | What it gates                                                           |
| ------------------------------ | ----------------------------------------------------------------------- |
| `QUERY_EXAMPLE_CREATE`         | Create a new snippet (the "Add query example" button on the list page). |
| `QUERY_EXAMPLE_UPDATE`         | Edit an existing snippet.                                               |
| `QUERY_EXAMPLE_DELETE`         | Delete an existing snippet.                                             |
| `QUERY_EXAMPLE_DATASET_CREATE` | Attach a snippet to a dataset (entity ↔ snippet link).                  |
| `QUERY_EXAMPLE_DATASET_DELETE` | Detach a snippet from a dataset.                                        |
| `QUERY_EXAMPLE_TERM_CREATE`    | Attach a snippet to a glossary term (term ↔ snippet link).              |
| `QUERY_EXAMPLE_TERM_DELETE`    | Detach a snippet from a glossary term.                                  |

## API surface

The full HTTP API for Query Examples is documented at [API Reference → Query Examples](/developer-guides/api-reference/query-examples.md) — 16 endpoints across three groups (CRUD, faceted search, per-entity/per-term lookup and linking), exposed by `QueryExampleController` and the Data Entity / Term controllers, with the seven `QUERY_EXAMPLE_*` permissions called out alongside the gated endpoints. To call them outside the in-app UI, authenticate with a [server-to-server (S2S) API key](/configuration-and-deployment/enable-security/authentication/s2s.md).

## Term-linking workflow

Glossary terms and Query Examples reinforce each other: a term defines what a concept *is* (e.g., "active customer"); a query example shows how to *compute it* against your real datasets. The platform supports both directions:

1. From a term's detail page, attach an existing Query Example. The term gains a "Query Examples" cluster surfacing the snippet alongside the linked datasets.
2. From a snippet's detail page, link the snippet to one or more terms. The snippet gains a "Terms" cluster.
3. The dedicated Query Example faceted search exposes a Terms facet — narrow snippets to ones that target a specific glossary term.

This closes the catalog loop: a reader landing on the term finds the canonical snippet; a reader landing on the snippet finds the term it implements.

## Query Example Details Page

Opening any Query Example from the list (`/data-modelling/query-examples/{id}`) lands on a three-tab details page. The active tab is driven by a `?tab=` URL query parameter:

| Tab                 | URL state                                 | What it shows                                                                                                                                                                         |
| ------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Overview**        | `?tab=overview` (or no `?tab=` — default) | The snippet's `definition` (prompt-style description) and the `query` body, both rendered through the platform's Markdown renderer.                                                   |
| **Linked Entities** | `?tab=linked-entities`                    | The data entities this snippet is attached to (tables, views, files). Read-only — unlinking requires opening the linked entity's own detail page and removing the snippet from there. |
| **Linked Terms**    | `?tab=linked-terms`                       | The glossary terms this snippet is linked to. Read-only with the same workflow note.                                                                                                  |

The tab strip carries small counter "hint badges" next to each tab name showing how many entries it contains.

{% hint style="warning" %}
**Arbitrary `?tab=` values render an empty body.** The page accepts the URL parameter verbatim — it does not validate that the value is one of the three known tokens above. A typo (`?tab=overiew`, `?tab=linked_entities` with underscore) or a future-renamed token lands the user on the page with **no active tab and a blank content area** — no error message, no "tab not found" placeholder. If you are deep-linking from another system, validate the token on your side before generating the URL.
{% endhint %}

{% hint style="info" %}
**The "Linked Terms" hint badge can understate when a snippet has many terms.** The Linked Entities badge reads the total from server-side pagination (it is correct across all pages). The Linked Terms badge reads `items.length` on the loaded slice (it understates if the term collection is large enough to paginate). The tab body itself shows all loaded terms; only the badge digit may differ from the total.
{% endhint %}

The details page does not carry a breadcrumb back to the list — use the **Data Modelling → Query Examples** left-rail tab to return to the listing, or the browser Back button.

## Known operator caveats

The Query Examples surface carries several behaviours that are non-obvious from the UI and the permission table alone. Each item below states what an operator might assume, what the platform actually does, and what to do today.

{% hint style="warning" %}
**The seven `QUERY_EXAMPLE_*` permissions are wired across three different controllers.** Configuring "Query Example access" in a single Policy is not enough — the gating endpoints live on three different surfaces:

When granting Query Example capability to a role, audit Policies on all three controllers. Restricting `QUERY_EXAMPLE_*` in one Policy scope (e.g., only the Query Example controller) leaves four of the seven permissions un-enforced on that role — operators can still attach / detach snippets from datasets or terms.
{% endhint %}

| Permissions                                    | Controller surface       | Endpoints                                                        |
| ---------------------------------------------- | ------------------------ | ---------------------------------------------------------------- |
| `QUERY_EXAMPLE_CREATE` / `_UPDATE` / `_DELETE` | Query Example controller | `POST/PUT/DELETE /api/queryexample/...`                          |
| `QUERY_EXAMPLE_DATASET_CREATE` / `_DELETE`     | Data Entity controller   | `POST/DELETE /api/dataentities/{id}/queryexample[/{example_id}]` |
| `QUERY_EXAMPLE_TERM_CREATE` / `_DELETE`        | Term controller          | `POST/DELETE /api/terms/{id}/queryexample[/{example_id}]`        |

{% hint style="warning" %}
**All read, search, and listing endpoints for Query Examples are open to every authenticated user — only the seven mutation permissions are RBAC-gated.** The mutation operations (CREATE / UPDATE / DELETE on snippets, dataset-link CREATE / DELETE, term-link CREATE / DELETE) check the permission table above. The listing surface (`GET /api/queryexample`), the per-snippet read (`GET /api/queryexample/{id}`), the faceted search endpoints, and the per-entity / per-term lookup endpoints all fall through to the platform's catch-all "any authenticated user" rule.

**Operator-visible consequence.** Every authenticated user reads every Query Example in the platform — title, description, query body, linked entities, linked terms — regardless of dataset RBAC, namespace scoping, or `exclude_from_search`. Under `auth.type=DISABLED`, the same reads are anonymous. Multi-team deployments expecting per-team query-example visibility cannot enforce it through the RBAC layer today. Treat Query Example content as catalog-read-collaborative; sensitive SQL bodies (production credentials, restricted column references, internal table aliases) should not be authored here, or should be enforced at the network perimeter via reverse-proxy rules.
{% endhint %}

{% hint style="info" %}
**The Query Example Markdown render is HTML-sanitised as of 0.28.0.** The `definition` (prompt-style description) and `query` (SQL body) fields are stored verbatim and rendered through the platform's shared Markdown renderer on the details page. Releases up to 0.27.x ran that renderer without an HTML-sanitisation pass, so HTML embedded in either field rendered for every viewer; **0.28.0 adds render-time sanitisation** to the shared Markdown renderer, so `<script>`, `javascript:` hrefs, and other raw-HTML payloads in a Query Example body are stripped when the snippet is displayed.

**Still review what you store.** Sanitisation is a render-time defence, not an input filter: the raw field value is stored verbatim and is readable by every authenticated user through the open read endpoints above. Restrict `QUERY_EXAMPLE_CREATE` and `QUERY_EXAMPLE_UPDATE` to operators reviewing the source of every value they paste in, and avoid bulk-importing Query Examples from untrusted external systems.
{% endhint %}

{% hint style="warning" %}
**The create / edit dialog has no client-side validation and no draft persistence.** The Query Example form validates only that the `definition` and `query` fields are non-empty — there is no length cap and no content preview. Values are stored verbatim; rendered Markdown is HTML-sanitised at display time as of 0.28.0 (see the note above).

The dialog also has **no dirty-form warning and no autosave**: closing the dialog through Escape, an outside-click, or browser back drops the entire in-progress body silently. For a SQL snippet of moderate size this is a real loss — minutes-to-hours of work disappear without recovery. Workaround: copy the SQL body to the clipboard before closing the dialog; treat the dialog as ephemeral until the upstream `handleNavigationWarning` hook ships.
{% endhint %}

{% hint style="info" %}
**The `definition` field is a plain text input at authoring time but renders through the Markdown renderer on the details page.** An author typing `**bold**` or `## Heading` into the definition field sees plain text in the form preview but rendered Markdown on the details page. Review the rendered details page after the first save to catch formatting surprises (rendered Markdown is HTML-sanitised as of 0.28.0 — see the render-sanitisation note above).
{% endhint %}

{% hint style="warning" %}
**Query Example mutations are not recorded on the Activity Feed.** Creating, updating, deleting, or linking / unlinking a Query Example produces no entry on the global Activity Feed and no entry on the per-entity Activity tab. There is no platform-side audit trail for Query Example changes today — auditor queries of "who edited which snippet when" cannot be answered from platform logs. The wider audit-scope picture and the compensating controls operators can apply are documented on the [Audit trail scope](/configuration-and-deployment/enable-security/audit-trail-scope.md) page; until the platform-side activity-event ships, instrument Query Example changes externally (PostgreSQL `pgaudit` on the `query_example` and `query_example_*` tables, or an API-gateway-level audit hook).
{% endhint %}

## Where to next

* [Data Modelling overview](/features/data-modelling.md) — parent section; pairs Query Examples with Relationships.
* [Relationships](/features/data-modelling/relationships.md) — the other Data Modelling sub-surface.
* [Authorization → Roles](/configuration-and-deployment/enable-security/authorization/roles.md) — wire the seven `QUERY_EXAMPLE_*` permissions onto your roles.
* [Audit trail scope](/configuration-and-deployment/enable-security/audit-trail-scope.md) — the cross-platform list of surfaces that emit Activity-Feed events versus those that do not.
* [API reference](/developer-guides/api-reference.md) — the full Ingress / management API.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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.opendatadiscovery.org/features/data-modelling/query-examples.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.
