Build Semantic Views and Connect to Tableau with Snowflake
Overview
Welcome to this hands-on guide! In this session, we'll walk you through an end-to-end journey that shows how to go from raw campaign data to a fully usable Snowflake Semantic View and seamlessly consume it in Tableau.
This guide is designed to be practical and visual—you'll follow along in a Snowflake Notebook and see how each piece fits together in a modern analytics workflow.
What You'll Learn
- How to load and explore campaign data in Snowflake
- How to automatically generate a Semantic View using the Semantic View Wizard
- How to query Semantic Views using standard SQL
- How to generate a Tableau Data Source (
.tds) file from a Semantic View - How to connect Tableau to Snowflake using the generated Semantic View
What You'll Build
By the end of this guide, you will have:
- A fully functional marketing analytics database with dimension and fact tables
- A Semantic View generated from an existing Tableau workbook
- A Tableau Data Source file that connects directly to your Semantic View
Prerequisites
- Access to a Snowflake account
- Snowflake account with ACCOUNTADMIN role (or equivalent privileges)
- Tableau Desktop installed (for the Tableau integration section)
- Basic familiarity with SQL and Snowflake UI
Access the Notebook
You can follow along with this guide using the companion Snowflake Notebook:
- Download the notebook from GitHub: Semantic_View_Autopilot.ipynb
- In Snowsight, navigate to Projects > Notebooks
- Click the down arrow next to + Notebook and select Import .ipynb file
- Upload the downloaded notebook file
- Select a database, schema, and warehouse for the notebook
- Click Create to import the notebook
Architecture
The Semantic View Autopilot workflow follows this architecture:
┌──────────────────────┐ ┌────────────────────────────┐ │ Campaign Data │ │ Existing Tableau Workbook │ │ (Snowflake Tables) │ │ (.twb file) │ └──────────┬───────────┘ └─────────────┬──────────────┘ │ │ ▼ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ Semantic View Autopilot "Fast-Gen" │ │ (Generate Semantic View from existing analytics) │ └──────────┬───────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────┐ ┌────────────────────────────┐ │ Snowflake Semantic │ │ Query History │ │ View (Metrics + Dims)│ │ (Real Usage Patterns) │ └──────────┬───────────┘ └─────────────┬──────────────┘ │ │ ▼ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ Semantic View Autopilot │ │ (Suggest verified queries using usage patterns) │ └──────────┬───────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ Downstream Consumers │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Snowflake │ │ Cortex │ │ Tableau │ │ Any SQL │ │ │ │ Intelligence│ │ Analyst API │ │ (via .tds) │ │ Client │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ └──────────────────────────────────────────────────────────────────────┘
Setup Environment
Create Database and Schema
First, let's set up the database and schema for our marketing analytics data. Run the following SQL in a Snowflake worksheet or notebook:
-- Switch to accountadmin role to create db, schema, and load data USE ROLE ACCOUNTADMIN; -- Create database and schema CREATE OR REPLACE DATABASE SVA_VHOL_DB; USE DATABASE SVA_VHOL_DB; CREATE SCHEMA IF NOT EXISTS SVA_VHOL_SCHEMA; USE SCHEMA SVA_VHOL_SCHEMA; -- Optional: allow anyone to see the agents in this schema GRANT USAGE ON DATABASE SVA_VHOL_DB TO ROLE PUBLIC; GRANT USAGE ON SCHEMA SVA_VHOL_DB.SVA_VHOL_SCHEMA TO ROLE PUBLIC;
Create File Format
Create a file format for loading CSV data:
-- Create file format for CSV files CREATE OR REPLACE FILE FORMAT CSV_FORMAT TYPE = 'CSV' FIELD_DELIMITER = ',' RECORD_DELIMITER = '\n' SKIP_HEADER = 1 FIELD_OPTIONALLY_ENCLOSED_BY = '"' TRIM_SPACE = TRUE ERROR_ON_COLUMN_COUNT_MISMATCH = FALSE ESCAPE = 'NONE' ESCAPE_UNENCLOSED_FIELD = '\134' DATE_FORMAT = 'YYYY-MM-DD' TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NULL_IF = ('NULL', 'null', '', 'N/A', 'n/a');
Load Marketing Data
Set Up Git Integration
Create an API integration and Git repository to access the demo data:
-- Create API Integration for GitHub (public repository access) CREATE OR REPLACE API INTEGRATION git_api_integration API_PROVIDER = git_https_api API_ALLOWED_PREFIXES = ('https://github.com/NickAkincilar/') ENABLED = TRUE; -- Create Git repository integration for the public demo repository CREATE OR REPLACE GIT REPOSITORY SVA_VHOL_REPO API_INTEGRATION = git_api_integration ORIGIN = 'https://github.com/NickAkincilar/Snowflake_AI_DEMO.git'; -- Create internal stage for copied data files CREATE OR REPLACE STAGE INTERNAL_DATA_STAGE FILE_FORMAT = CSV_FORMAT COMMENT = 'Internal stage for copied demo data files' DIRECTORY = ( ENABLE = TRUE) ENCRYPTION = (TYPE = 'SNOWFLAKE_SSE');
Copy Data Files
Fetch the repository and copy data files to the internal stage:
-- Fetch the latest from the repository ALTER GIT REPOSITORY SVA_VHOL_REPO FETCH; -- Copy data files from Git repository to internal stage COPY FILES INTO @INTERNAL_DATA_STAGE FROM @SVA_VHOL_REPO/branches/main/data/; -- Copy unstructured docs (including Tableau workbook) COPY FILES INTO @INTERNAL_DATA_STAGE/unstructured_docs/ FROM @SVA_VHOL_REPO/branches/main/unstructured_docs/; -- Refresh directory table ALTER STAGE INTERNAL_DATA_STAGE REFRESH;
Create Dimension Tables
Create the dimension tables for campaigns, channels, and products:
-- Create CAMPAIGN_DIM table CREATE OR REPLACE TABLE CAMPAIGN_DIM ( campaign_key INT, campaign_id VARCHAR(50), campaign_name VARCHAR(200), objective VARCHAR(100), start_date DATE, end_date DATE, budget DECIMAL(15,2), status VARCHAR(50) ); COPY INTO CAMPAIGN_DIM FROM @INTERNAL_DATA_STAGE/campaign_dim.csv FILE_FORMAT = CSV_FORMAT ON_ERROR = 'CONTINUE'; -- Create CHANNEL_DIM table CREATE OR REPLACE TABLE CHANNEL_DIM ( channel_key INT, channel_id VARCHAR(50), channel_name VARCHAR(100), channel_type VARCHAR(50), platform VARCHAR(100) ); COPY INTO CHANNEL_DIM FROM @INTERNAL_DATA_STAGE/channel_dim.csv FILE_FORMAT = CSV_FORMAT ON_ERROR = 'CONTINUE'; -- Create PRODUCT_DIM table CREATE OR REPLACE TABLE PRODUCT_DIM ( product_key INT, product_id VARCHAR(50), product_name VARCHAR(200), category VARCHAR(100), subcategory VARCHAR(100), price DECIMAL(10,2) ); COPY INTO PRODUCT_DIM FROM @INTERNAL_DATA_STAGE/product_dim.csv FILE_FORMAT = CSV_FORMAT ON_ERROR = 'CONTINUE';
Create Fact Table
Create the marketing campaign fact table:
-- Create MARKETING_CAMPAIGN_FACT table CREATE OR REPLACE TABLE MARKETING_CAMPAIGN_FACT ( fact_key INT, date DATE, campaign_key INT, channel_key INT, product_key INT, impressions INT, clicks INT, spend DECIMAL(15,2), conversions INT, revenue DECIMAL(15,2), leads_generated INT ); COPY INTO MARKETING_CAMPAIGN_FACT FROM @INTERNAL_DATA_STAGE/marketing_campaign_fact.csv FILE_FORMAT = CSV_FORMAT ON_ERROR = 'CONTINUE';
Verify Data Load
Verify the tables were created successfully:
-- List the tables SHOW TABLES;
Run Sample Queries
Before creating the Semantic View, let's run some sample queries that the Semantic View Autopilot can use to suggest model improvements and verified queries.
Marketing Performance by Month
SELECT DATE_TRUNC('month', mcf.date) AS month, SUM(mcf.spend) AS total_spend, SUM(mcf.impressions) AS total_impressions, SUM(mcf.leads_generated) AS total_leads, SUM(mcf.spend) / NULLIF(SUM(mcf.leads_generated), 0) AS cost_per_lead, SUM(mcf.leads_generated) / NULLIF(SUM(mcf.impressions), 0) AS lead_conversion_rate FROM MARKETING_CAMPAIGN_FACT mcf GROUP BY 1 ORDER BY 1;
Channel Efficiency Analysis
SELECT cd.channel_name, SUM(mcf.spend) AS total_spend, SUM(mcf.leads_generated) AS total_leads, SUM(mcf.spend) / NULLIF(SUM(mcf.leads_generated), 0) AS cost_per_lead FROM MARKETING_CAMPAIGN_FACT mcf JOIN CHANNEL_DIM cd ON mcf.channel_key = cd.channel_key GROUP BY 1 HAVING SUM(mcf.leads_generated) > 0 ORDER BY cost_per_lead ASC, total_leads DESC;
Top Campaigns by Leads
SELECT c.campaign_name, c.objective, SUM(mcf.leads_generated) AS total_leads, SUM(mcf.spend) AS total_spend, SUM(mcf.impressions) AS total_impressions, SUM(mcf.spend) / NULLIF(SUM(mcf.leads_generated), 0) AS cpl FROM MARKETING_CAMPAIGN_FACT mcf JOIN CAMPAIGN_DIM c ON mcf.campaign_key = c.campaign_key GROUP BY 1, 2 ORDER BY total_leads DESC LIMIT 10;
Create Semantic View
Use the Semantic View Wizard
Now let's create a Semantic View using the Semantic View Wizard with an existing Tableau workbook as context:
- Navigate to the Semantic View wizard by going to "AI & ML > Analyst" from the left side menu in Snowflake
- Pick
SVA_VHOL_DB.SVA_VHOL_SCHEMAfrom the dropdown - Select "Create New Semantic View"
Note: Be sure to use the ACCOUNTADMIN role or a role that has ownership rights on SVA_VHOL_DB.SVA_VHOL_SCHEMA.
- Name your semantic view
SVA_MARKETING_SVand click "Next" - In the following screen, select "Tableau Files" as your context
- Pick
SVA_VHOL_SCHEMA.INTERNAL_DATA_STAGEand navigate to the/unstructured_docs/BI_dashboardsfolder - Select the
CampaignMetricsDash.twbfile and click "Create and Save"
Test the Semantic View
On the next screen you will see a "first pass" version of a Snowflake Semantic View based on the imported .twb file.
Test it out by going to the "Playground" tab in the right-hand panel and asking:
"Show me the top 10 most expensive products based on cost per lead"
Congratulations! You just went from "zero-to-semantic-view" in 1 minute!
Query with Standard SQL
Understanding Standard SQL for Semantic Views
Semantic View Standard SQL in Snowflake allows you to write ANSI-style SQL queries against semantic views.
Example Query
-- Switch to the correct context USE ROLE ACCOUNTADMIN; USE DATABASE SVA_VHOL_DB; USE SCHEMA SVA_VHOL_SCHEMA; -- Standard SQL query against the semantic view SELECT -- dimensions and facts can be selected directly product_name, -- metrics must be aggregated using AGG, MIN, MAX, or ANYVALUE AGG(cost_per_lead) as total_cost_per_lead FROM -- directly reference the semantic view name SVA_MARKETING_SV -- you must include a GROUP BY if your SELECT statement includes any metrics GROUP BY ALL ORDER BY total_cost_per_lead DESC LIMIT 10;
Note: When querying Semantic Views with Standard SQL, remember:
- Dimensions and facts can be selected directly
- Metrics must be aggregated using
AGG,MIN,MAX, orANYVALUE - You must include a
GROUP BYclause if your SELECT statement includes any metrics
Generate Tableau TDS File
About the TDS Export Function
Snowflake has a system function that automatically generates a Tableau Data Source (.tds) file that points directly to the relevant Snowflake Semantic View with:
- A pre-configured connection
- Folders for organization
- Well-mapped metrics and dimensions
You can generate a TDS file with this statement:
SELECT SYSTEM$EXPORT_TDS_FROM_SEMANTIC_VIEW('SVA_VHOL_DB.SVA_VHOL_SCHEMA.SVA_MARKETING_SV');
Using the TDS Generator App
For a more user-friendly experience, you can use the following Python code in a Snowflake Notebook to generate and download the TDS file:
import streamlit as st from snowflake.snowpark.context import get_active_session def generate_and_download_tds(): """Clean interface for TDS generation and download""" st.title("TDS Generator") st.write("Generate Tableau Data Source files from Snowflake Semantic Views") # Input section semantic_view = st.text_input( "Semantic View Name", value="SVA_VHOL_DB.SVA_VHOL_SCHEMA.SVA_MARKETING_SV", help="Enter the fully qualified semantic view name" ) if st.button("Generate TDS", type="primary"): if not semantic_view: st.error("Please enter a semantic view name") return try: # Get Snowflake session session = get_active_session() # Call the system function with st.spinner("Generating TDS file..."): result = session.sql( f"SELECT SYSTEM$EXPORT_TDS_FROM_SEMANTIC_VIEW('{semantic_view}');" ).collect() tds_content = result[0][0] # Check for errors if tds_content.startswith("<!-- Error"): st.error(f"Generation failed: {tds_content}") return # Success - show download st.success("TDS file generated successfully") # Create filename view_name = semantic_view.split('.')[-1] if '.' in semantic_view else semantic_view filename = f"{view_name}_Semantic_View.tds" # Download button st.download_button( label="Download TDS", data=tds_content, file_name=filename, mime="application/xml" ) except Exception as e: st.error(f"Error: {str(e)}") # Run the app generate_and_download_tds()
Run this cell and click "Generate TDS", then open the .tds file using Tableau!
Connect Tableau
Open the TDS File
- Locate the downloaded
.tdsfile on your computer - Double-click the file to open it in Tableau Desktop
- Tableau will automatically connect to Snowflake using the pre-configured connection settings
Authenticate to Snowflake
When prompted, enter your Snowflake credentials to authenticate the connection.
Explore Your Data
Once connected, you'll see:
- All dimensions and metrics from your Semantic View organized in folders
- Pre-configured relationships and hierarchies
- Ready-to-use calculated fields based on your Semantic View metrics
You can now build visualizations and dashboards using the semantic layer you created in Snowflake!
Conclusion And Resources
Congratulations! You've successfully built an end-to-end workflow from raw campaign data to a fully functional Snowflake Semantic View, and connected it to Tableau for visualization. You've learned how to leverage the Semantic View Wizard to quickly generate semantic models from existing Tableau workbooks.
What You Learned
- How to set up a Snowflake environment for marketing analytics data
- How to create a Semantic View using the Semantic View Wizard with Tableau workbook context
- How to query Semantic Views using standard SQL
- How to generate and use Tableau Data Source files from Semantic Views
Related Resources
Documentation:
Happy analyzing!
This content is provided as is, and is not maintained on an ongoing basis. It may be out of date with current Snowflake instances