There are a number of options available to implement row level security in Tableau. You would use row level security within Tableau for circumstances where access to only specific rows of your data set are required, for example maybe sales data can only be seen via people within that sales hierarchy – i.e. only the management of an employee can see the sales of that employee.
Often the clearest way to show how to use row level security is to include some examples. Assuming we have the following data:
There are 3 main ways to implement row level security in Tableau.
1. Connect Live
If connecting live a join to the permissions data can be carried out at the database layer, only returning those rows that are relevant.
- Is the most flexible and easiest to implement
- The underlying data set needs to be highly optimised to allow connecting live
2. Create a string of usernames for each row of data and use the CONTAINS function to look up
- Can be used within an extract (tde)
- The string has to be built and added to each row of the underlying data
- Instinctively feels non-performant, string comparisons generally aren’t fast (although in reality the performance isn’t as bad as it feels it should be)
- There’s a limit to the size of the string, depending on how the string is built. i.e. a SQL stored proc has an approx 3000 limit, the dependency is on the limits of the field size in the underlying data
- Building the data extract file is slower due to pulling in a large additional string field in the data set
3. Data blend against a permissions file
- Means pulling in a simple flat permissions file into the Tableau workbook, which is simple and not a large impact on the size of the file
- The data blending join field needs to be included in every worksheet on the dashboard, which can make the worksheets significantly more complex – i.e. if trying to build a summary sheet such as a Total sheet, the summing of values will have to become more complex table calcuations to ignore the join field within the worksheet
Which option you choose to take depends on your individual circumstances. I’ve used 1 and 2 in real world situations. 3 has always been too complex as the join field needs to appear in all views.
To use option 2 you need a formula in the filters to do the actual lookup, something like: CONTAINS([YourString],USERNAME()), setting the filter value to TRUE.