> For the complete documentation index, see [llms.txt](https://documentation.immuta.com/latest/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.immuta.com/latest/governance/author-policies-for-data-access-control/authoring-policies-in-secure/data-policies/reference-guides/lookup-tables.md).

# Lookup Tables

If user metadata is stored in a table in the same data platform where a policy is enforced, it is not necessary to move that user metadata in Immuta. Instead it can be referenced directly using [custom WHERE](/latest/governance/author-policies-for-data-access-control/authoring-policies-in-secure/data-policies/reference-guides/custom-where-clause-functions.md) functions in data policies.

Below is an example row-level policy that leverages a lookup table to dynamically drive access to rows in a table:

| CREDIT\_CARD\_NUMBER | TRANSACTION\_LOCATION | TRANSACTION\_TIME | ACCESS\_LEVEL |
| -------------------- | --------------------- | ----------------- | ------------- |
| 0123456789           | Lewes, DE             | 00:07:34          | 4             |
| 9876543210           | College Park, MD      | 09:16:08          | 8             |

The final column in the table, ACCESS\_LEVEL, defines who can see that row of data.

Now consider the following hierarchy:

<figure><img src="/files/h7KY6AgC9cwwZCLxXo3x" alt=""><figcaption></figcaption></figure>

In this diagram, there are 11 different access levels (AL) to data and the tree defines access. For example, if a user has `Vegetables`, they get access levels 2, 3, 4, 9, 10, and 11. If a user has `Pear`, they only get access level 8. In other words, a user with `Vegetables` would see the first row of the above table, a user with `Pear` would see the second row of the above table, and a user with `Food` would see both rows of the table.

Taking the example further, that hierarchy tree is represented as a table in the data platform that we wish to use to drive the row-level policy:

| ACCESS\_LEVEL |    ROOT    |
| :-----------: | :--------: |
|       1       |    Food    |
|       2       |    Food    |
|       3       |    Food    |
|       4       |    Food    |
|       5       |    Food    |
|       6       |    Food    |
|       7       |    Food    |
|       8       |    Food    |
|       9       |    Food    |
|       10      |    Food    |
|       11      |    Food    |
|       2       | Vegetables |
|       3       | Vegetables |
|       4       | Vegetables |
|       9       | Vegetables |
|       10      | Vegetables |
|       11      | Vegetables |
|       5       |   Fruits   |
|       6       |   Fruits   |
|       7       |   Fruits   |
|       8       |   Fruits   |
|       4       |   Carrots  |
|       9       |    Leafy   |
|       10      |    Leafy   |
|       11      |    Leafy   |
|       5       |   Orange   |
|       6       |   Orange   |
|       7       |   Orange   |
|       8       |    Pear    |
|       10      |   Lettuce  |
|       11      |   Lettuce  |

That hierarchy lookup table can be referenced in the row-level policy as user metadata like this:

> `@columnTagged('access_level')` IN (SELECT ACCESS\_LEVEL from \[lookup table] where `@attributeValuesContains('user_level', 'ROOT')`)

Walking through the policy step-by-step:

* `@columnTagged('access_level')`: This allows us to target multiple tables with an ACCESS\_LEVEL column that needs protecting with a single policy. Simply tag all the ACCESS\_LEVEL columns with the `access_level` tag and this policy would apply to all of them.
* `IN (SELECT ACCESS_LEVEL from [lookup table]`: This is selecting the matching ACCESS\_LEVEL from the lookup table to use as the IN clause for filtering the actual business table.
* `where @attributeValuesContains('user_level', 'ROOT')`: This is comparing the user's attribute `user_level` to the value in the ROOT column, and if there's a match, that ACCESS\_LEVEL is used for filtering in the previous step. See the [custom WHERE](/latest/governance/author-policies-for-data-access-control/authoring-policies-in-secure/data-policies/reference-guides/custom-where-clause-functions.md) documentation for more details on these functions.

So, you can then add metadata to your users in Immuta, such as `Vegetables` or `Pear` and that will result in them seeing the appropriate rows in the business table in question.

The above example used a row-level policy, but it could instead do cell masking using the same technique:

> Mask columns tagged `Credit Card Number` using hashing where `@columnTagged('access_level')` NOT IN (SELECT ACCESS\_LEVEL from \[lookup table] where `@attributeValuesContains('user_level', 'ROOT')`)

In this case, the credit card number will be masked if the access\_level is not found for the user for that row.

Even if not using a lookup table, the power of the `@columnTagged('tag name')` function is apparent for applying your masking or row-level policies at scale.


---

# 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, and the optional `goal` query parameter:

```
GET https://documentation.immuta.com/latest/governance/author-policies-for-data-access-control/authoring-policies-in-secure/data-policies/reference-guides/lookup-tables.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
