This QuickStart introduces and demonstrates Sigma embedding using parameterized queries.
Parameterized queries are quite useful when embedded customers have per-customer databases with the same schema.
While there are several ways to store customer data, this method is fairly common.
To accomplish this in Sigma, we will use queries and leverage custom user attributes.
End users are authenticated by the parent application. When the user navigates to a parent page containing embedded Sigma content, the parent sends a request to Sigma via the embed API, containing query parameters (user attributes) that specify the database and schema names. Sigma parses that request, and applies the user attributes to the SQL query. The query is then evaluated by Sigma and if required, sent to the cloud data warehouse.
How Sigma performs calculations is beyond the scope of this QuickStart, but covered in-depth here.
This is different from other options that Sigma offers to handle common architectural designs.
Other options include:
Snowflake connection swapping.
Embedding 09: Dynamic Role Switching.
Semi-technical users who will be aiding in the planning or implementation of Sigma. Limited SQL and technical data skills are needed to do this QuickStart. It does assume some common computer skills like installing software, using Terminal, navigating folders and edit/copy/paste operations.
This QuickStart assumes you have already taken the QuickStart Embedding 1: Prerequisites so that you have a sample environment to complete the tasks in this QuickStart.
We also recommend you take the the QuickStart Embedding 3: Secure Embedding as we will build on that content.
Sigma provides support for the most common multi-tenant architectures, widely used by businesses today to provide portal access while ensuring data separation.
The most common examples of this are:
1: One Snowflake account, per-customer databases:
Database names are different, but schema names are the same.
2: One Snowflake account, single database, per-customer schema:
Database and schema names are different.
3: Two Snowflake accounts with databases and/or schemas that have the same structure but different names:
This requires the previously mentioned connection-swapping user attribute along with custom user attributes for database and schema names.
The basic design pattern with custom user attributes provides enough flexibility to allow customers to select the model that best suits their architectural needs.
We listed three common use cases, but regardless, the fundamental design pattern will be the same. In light of that, we will focus on use case #2 for demonstration, since the steps will be common to the other two use cases, with some variations in functionality
Imagine a scenario where Sigma content is embedded into a customer's SaaS application that is used by multiple clients.
Each client accesses the same type of data (e.g., store sales data), but their data is stored in the same Snowflake account.
The database and schema names reflect the actual name of each client.
For our demonstration, let's assume the SaaS provider is a national retail distributor who has clients selling goods in specific regions of the United States.
The distributor has a client portal they want to embed Sigma in.
They prefer that all clients use a common dashboard to ease training, support, and related development work as new clients are on-boarded.
There are two clients, Client_A
and Client_B
.
The data consists of typical retail store sales data.
Each client has a STORE_SALES
table with the same structure, but the sales data is specific to each client.
To accomplish this, we will use our trial Snowflake account and create per-customer databases and schemas.
We have created the following Snowflake script to automate the process of creating roles, and sample data.
Log into Snowflake as ACCOUNTADMIN
.
Open a new SQL Worksheet
.
The following script creates roles for Client_A
and Client_B
, sets up databases and schemas for each client, grants appropriate access permissions, and populates sample sales data into the respective STORE_SALES
tables.
It also creates the same for Client_Default
, but table data only has one row of dummy data. This will be used as our default setting later on in the Sigma configuration. We do this so that in the event the parent application fails to send values for database and/or schema, the default will be used and not expose other customer data.
Copy and paste this code into the worksheet:
-- Use the ACCOUNTADMIN role and COMPUTE_WH warehouse
USE ROLE ACCOUNTADMIN;
USE WAREHOUSE COMPUTE_WH;
-- Step 1: Create Roles
CREATE OR REPLACE ROLE Client_A_Role;
CREATE OR REPLACE ROLE Client_B_Role;
CREATE OR REPLACE ROLE Client_Default_Role;
-- Step 2: Create Databases and Schemas
CREATE OR REPLACE DATABASE Client_A_DB;
CREATE OR REPLACE SCHEMA Client_A_DB.Client_A_Schema;
CREATE OR REPLACE DATABASE Client_B_DB;
CREATE OR REPLACE SCHEMA Client_B_DB.Client_B_Schema;
CREATE OR REPLACE DATABASE Client_Default_DB;
CREATE OR REPLACE SCHEMA Client_Default_DB.Client_Default_Schema;
-- Step 3: Create Tables and Insert Sample Data
-- Client_A
CREATE TABLE Client_A_DB.Client_A_Schema.STORE_SALES (
sale_id INT,
sale_date DATE,
store_id INT,
amount DECIMAL(10, 2)
);
INSERT INTO Client_A_DB.Client_A_Schema.STORE_SALES (sale_id, sale_date, store_id, amount) VALUES
(1, '2024-01-01', 100, 100.00),
(2, '2024-02-02', 200, 200.00),
(3, '2024-03-03', 300, 300.00),
(4, '2024-04-04', 400, 400.00),
(5, '2024-05-05', 500, 500.00);
-- Client_B
CREATE TABLE Client_B_DB.Client_B_Schema.STORE_SALES (
sale_id INT,
sale_date DATE,
store_id INT,
amount DECIMAL(10, 2)
);
INSERT INTO Client_B_DB.Client_B_Schema.STORE_SALES (sale_id, sale_date, store_id, amount) VALUES
(1, '2024-06-06', 600, 600.00),
(2, '2024-07-07', 700, 700.00),
(3, '2024-08-08', 800, 800.00),
(4, '2024-09-09', 900, 900.00),
(5, '2024-10-10', 1000, 1000.00);
-- Client_Default
CREATE TABLE Client_Default_DB.Client_Default_Schema.STORE_SALES (
sale_id INT,
sale_date DATE,
store_id INT,
amount DECIMAL(10, 2)
);
INSERT INTO Client_Default_DB.Client_Default_Schema.STORE_SALES (sale_id, sale_date, store_id, amount) VALUES
(1, '2024-01-01', 0, 0.00);
-- Step 4: Grant Permissions
-- Client_A
GRANT USAGE ON DATABASE Client_A_DB TO ROLE Client_A_Role;
GRANT USAGE ON SCHEMA Client_A_DB.Client_A_Schema TO ROLE Client_A_Role;
GRANT SELECT ON ALL TABLES IN SCHEMA Client_A_DB.Client_A_Schema TO ROLE Client_A_Role;
-- Client_B
GRANT USAGE ON DATABASE Client_B_DB TO ROLE Client_B_Role;
GRANT USAGE ON SCHEMA Client_B_DB.Client_B_Schema TO ROLE Client_B_Role;
GRANT SELECT ON ALL TABLES IN SCHEMA Client_B_DB.Client_B_Schema TO ROLE Client_B_Role;
-- Client_Default
GRANT USAGE ON DATABASE Client_Default_DB TO ROLE Client_Default_Role;
GRANT USAGE ON SCHEMA Client_Default_DB.Client_Default_Schema TO ROLE Client_Default_Role;
GRANT SELECT ON ALL TABLES IN SCHEMA Client_Default_DB.Client_Default_Schema TO ROLE Client_Default_Role;
-- Step 5: Grant Permissions to ACCOUNTADMIN
GRANT SELECT ON ALL TABLES IN SCHEMA Client_A_DB.Client_A_Schema TO ROLE ACCOUNTADMIN;
GRANT SELECT ON ALL TABLES IN SCHEMA Client_B_DB.Client_B_Schema TO ROLE ACCOUNTADMIN;
GRANT SELECT ON ALL TABLES IN SCHEMA Client_Default_DB.Client_Default_Schema TO ROLE ACCOUNTADMIN;
GRANT USAGE ON WAREHOUSE COMPUTE_WH TO ROLE ACCOUNTADMIN;
-- Step 6: Verify Grants - OPTIONAL VERIFICATION
-- Verify grants for Client_A_Role
-- SHOW GRANTS TO ROLE Client_A_Role;
-- Verify grants for Client_B_Role
-- SHOW GRANTS TO ROLE Client_B_Role;
-- Verify grants for Client_Default_Role
-- SHOW GRANTS TO ROLE Client_Default_Role;
-- Verification Queries
-- SELECT * FROM Client_A_DB.Client_A_Schema.STORE_SALES;
SELECT * FROM Client_B_DB.Client_B_Schema.STORE_SALES;
-- SELECT * FROM Client_Default_DB.Client_Default_Schema.STORE_SALES;
Execute the script. When it completes, you will see some row data for Client_B
:
Log into Sigma as Administrator
.
Navigation to Administration
> Teams
and create add the CLIENT_A
and CLIENT_B
teams.
No need to assign anyone to these teams now.
We need to create a few attributes that will serve as placeholders for values that will be passed from the parent application at runtime.
Navigate to Administration
> User Attributes
and click Create Attribute
.
Give the attribute the name Client_DB
, set the default value to Client_Default_DB
and click Create
:
Repeat the process, creating new a attribute for Client_Schema
, taking care to assign the expected default; Client_Default_Schema
.
Repeat the process one more time, creating new a attribute for Client_Role
, taking care to assign the expected default; Client_Default_Role
.
Create a new connection in Administration
> Connections
and name itParameterized Queries QuickStart
.
Configure the rest of the connection as shown below, adjusting for your Snowflake account.
Click the Browse connection
button and make sure you can see all the client database/schema:
Click the Explore
button to open the STORE_SALES
table in a new Sigma workbook. It does not matter if you were browsing the Client_A
or Client_B
connection:
Use the Save As
button to create the new workbook named Parameterized Queries QuickStart
.
It is really great that Sigma can just launch a connection to data directly into a familiar spreadsheet interface, creating optimized SQL on-the-fly for us in seconds.
However, we want to have a single workbook that provides all clients a common interface, using each clients data only.
The table on this page does not do that, so lets delete it:
To accomplish that, we need to create a table based on parameterized SQL instead.
In the Element panel
, click Table
and SQL
:
Select our new Parameterized Queries QuickStart
connection:
We are now able to create a custom SQL statement to return data instead of Sigma doing it for us. We will use this to create a parameterized query.
Copy and paste this code and click the Run
button:
SELECT * FROM CLIENT_A_DB.CLIENT_A_SCHEMA.STORE_SALES
While our query is not yet parameterized, this verifies that we can retrieve data as expected:
Now replace the code to use our user attributes instead:
SELECT * FROM {{#raw system::CurrentUserAttributeText::Client_DB}}.{{#raw system::CurrentUserAttributeText::Client_Schema}}.STORE_SALES
We are present with the single row of data from the Client_Default_DB
table:
Recall that when we created the user attributes for Client_DB
and Client_Schema
we set default values. This is why we are seeing data still, instead of a SQL error.
It may also be nice to know which user is accessing data when we test the embed later. This is easy enough to do.
Add a new Text
element and configure it by typing =CurrentUserEMail()
and clicking the :
Click Publish
.
To be able to test this workbook, we need to share it with the two teams.
In the drop menu for the workbook, click Share
:
Add the CLIENT_A
and CLIENT_B
teams. Det the permission to Can View
and select Share
:
Open the workbook's menu and click Embedding
. Create a Secure
embed for the Entire Workbook
and copy the Embed path
:
Store the Embed path
in a text file; we will use that later.
If you already have a valid set of client credentials, you can skip this part. If not, navigate to Administration
> Developer Access
and click the Create new
button.
Select Embedding
and add Sigma administrator account as the Owner
. Click Create
:
Sigma will present the Client Id
and Secret
one time for you to copy off to a safe location. Make those copies; we will these values later.
Close the Access Credentials
modal once you have copied the two values.
For testing, we will use the same Node.js framework that was setup during the QuickStart: Embedding 01: Prerequisites.
To save time, we have provided the required project files for download.
Download the project files here
Unzip the folder sigma_parameterized_queries.zip
and open a Terminal session from it (right-click and select `):
Run the command:
supervisor embed-api.js
The expected response is:
Open the file embed-api.js
and change the values for YOUR_EMBED_PATH
, YOUR_EMBED_SECRET
and YOUR_CLIENT_ID
for your configuration:
Save the changes.
Scroll to section #6 in the file. We have created sections for Client_A
and Client_B
.
Client_B
's configuration is commented out for now ("//"):
Check our embed in a browser, we will see only data for Client_A
:
localhost:3000
In this configuration, Snowflake's role-based access control is being used to control data access. Embed users are authenticated by the parent application and pass information to Sigma (after they are authenticated) via the Sigma embed API. Embed users are automatically added to Sigma (for logging purposes) and assigned to a team, based on the parent applications instruction.
For example, once we used our local embed api for Client_A
, a user was automatically created in Sigma and assigned to the Client_A
team:
Commenting out the Client A
lines and uncommenting the Client B
lines will result in only Client_B
rows appearing.
Save the file embed-api.js
.
Refreshing the browser for the embed results in Client_B
data being displayed from the second Snowflake connection:
We can now deploy a Sigma dashboard that is shared across multiple clients, ensuring data isolation through parameterized queries in Sigma.
In this QuickStart we learned how to setup Sigma embedding using parametrized queries with Snowflake and the different use-cases where it is useful.
Additional Resource Links
Blog
Community
Help Center
QuickStarts
Be sure to check out all the latest developments at Sigma's First Friday Feature page!