The Analyze Direct data model includes two types of identifier fields: Surrogate Key fields (for relationships) and Guaranteed Unique ID fields (for persistent references). This article explains how to use each field type to keep joins, filters, saved reports, and change tracking reliable over time.
Key Fields and ID Fields in Analyze Direct
This section defines Surrogate Key fields and Guaranteed Unique ID fields, and explains when to use each.
Identifier Field Types
Analyze Direct uses the following identifier field types:
- Surrogate Key fields (for example,
COURSE_KEY). - Guaranteed Unique ID fields (for example,
COURSE_ID).
What Is a Surrogate Key?
A Surrogate Key is a system-generated internal identifier used to maintain relationships between tables in the data warehouse.
Examples
The following are common Surrogate Key fields:
COURSE_KEYUSER_KEYSESSION_KEY
Characteristics
Surrogate Keys are:
- Numeric.
- Optimized for joins and warehouse performance.
- Used to relate fact and dimension tables.
- Not guaranteed to remain constant over time.
- May change during data rebuilds, migrations, or model updates.
Surrogate Keys are designed for internal relational mechanics and not long-term filtering.
What Is a Guaranteed Unique Identifier?
A Unique ID field represents the true, immutable business identifier of the object.
Examples
The following are common Unique ID fields:
COURSE_IDUSER_IDSESSION_ID
Characteristics
Unique ID fields are:
- Guaranteed unique.
- Immutable for the life of the object.
- Safe for saved filters, integrations, and persistent reporting.
If a report needs to consistently reference the same course over time, the filter must use COURSE_ID and not COURSE_KEY.
Key Takeaway
Use Surrogate Keys for joins and Unique IDs for filters and persistent references.
- Surrogate Keys maintain relationships.
- Unique IDs provide an immutable reference.
Surrogate Key values are subject to change. If a filter must remain correct over time, it must use the immutable *_ID field and not the *_KEY field.
Best Practices in SQL
Use Surrogate Keys to join related tables, and use Unique IDs when filtering for specific records.
Correct: Using Surrogate Keys in JOIN Statements
Surrogate Keys are appropriate when joining tables within your Snowflake warehouse.
In this example, COURSE_KEY maintains the table relationship and COURSE_ID is returned as the stable reference.
SELECT c.COURSE_ID, c.COURSE_NAME, e.USER_ID, e.COMPLETION_DATE FROM FACT_ENROLLMENT e JOIN DIM_COURSE c ON e.COURSE_KEY = c.COURSE_KEY;
Correct: Using Unique IDs in WHERE Clauses
When filtering for specific records, always use immutable ID fields.
This helps ensure filters continue to work correctly and reports remain accurate after warehouse updates.
SELECT USER_ID, COMPLETION_DATE FROM FACT_ENROLLMENT WHERE COURSE_ID = '964e6eee-56dd-4d4c-9f77-10b89a52a0fe';
Incorrect: Filtering with Surrogate Keys
Filtering with Surrogate Keys is risky because key values can be regenerated or remapped. This can cause saved reports to silently return incorrect results or filters to break without warning.
SELECT USER_ID, COMPLETION_DATE FROM FACT_ENROLLMENT WHERE COURSE_KEY = 12345;
Best Practice Pattern
Use the following pattern in your SQL and reporting tools:
- JOIN using Surrogate Keys.
- FILTER using immutable Unique Identifiers.
Example Combining Both
This example joins using COURSE_KEY and filters using COURSE_ID.
SELECT c.COURSE_ID, COUNT(*) AS Total_Completions FROM FACT_ENROLLMENT e JOIN DIM_COURSE c ON e.COURSE_KEY = c.COURSE_KEY WHERE c.COURSE_ID IN ( '964e6eee-56dd-4d4c-9f77-10b89a52a0fe', 'b85a49c4-8368-4223-8596-a643d2145ed4' ) GROUP BY c.COURSE_ID;
Field Use Case Summary
The following table summarizes when to use each field type.
| Joining tables | Surrogate Key (*_KEY) |
| Filtering records | Unique ID (*_ID) |
| Saved reports | Unique ID |
| Power BI slicers | Unique ID |
| Persistent integration references | Unique ID |
Proper Use in Upserts
An upsert operation updates an existing row, or inserts a new row if one does not exist. This requires a stable way to identify whether a record already exists.
Analyze Direct provides a read-only version of your LMS data in your Snowflake warehouse. Actions described in this section can be performed on copies of your LMS data, for example, COPY_OF_COURSE is a copy of DIM_COURSE.
Always match rows using the Unique Identifier (*_ID), never the Surrogate Key (*_KEY).
Why Surrogate Keys Must Not Be Used in Upserts
Surrogate Keys are generated after insertion, may change across data loads, and do not represent real-world identity. Using them in upserts causes duplicate records, failed matches, and data corruption over time.
Incorrect: Upsert Using a Surrogate Key
The following example shows an incorrect merge statement that uses COURSE_KEY (a Surrogate Key) as the match condition. The source system typically does not control COURSE_KEY, keys may not align between staging and target, and the result is duplicate or missed records.
MERGE INTO COPY_OF_COURSE target
USING STAGING_COURSE source
ON target.COURSE_KEY = source.COURSE_KEY -- Incorrect: surrogate key
WHEN MATCHED THEN
UPDATE SET target.COURSE_NAME = source.COURSE_NAME
WHEN NOT MATCHED THEN
INSERT (COURSE_KEY, COURSE_NAME)
VALUES (source.COURSE_KEY, source.COURSE_NAME);
Correct: Upsert Using a Unique Identifier
The following example shows a correct merge statement that uses COURSE_ID (a Unique Identifier) as the match condition. Since COURSE_ID is stable and meaningful, this approach ensures correct matching across loads and prevents record duplication.
MERGE INTO COPY_OF_COURSE target
USING STAGING_COURSE source
ON target.COURSE_ID = source.COURSE_ID -- Correct: unique identifier
WHEN MATCHED THEN
UPDATE SET
target.COURSE_NAME = source.COURSE_NAME,
target.LAST_UPDATED_DATE = CURRENT_TIMESTAMP
WHEN NOT MATCHED THEN
INSERT (COURSE_ID, COURSE_NAME, CREATED_DATE)
VALUES (source.COURSE_ID, source.COURSE_NAME, CURRENT_TIMESTAMP);
Common Upsert Errors
The following table describes common errors made when writing upsert statements and the impact of each.
| Error | Result |
Matching on *_KEY | Duplicate records or missed updates |
| Using changing fields (for example, name) to match | Incorrect merges |
Not enforcing uniqueness on *_ID | Data drift over time |
| Re-generating Surrogate Keys for existing records | Broken table relationships |
Key Takeaway
Surrogate Keys maintain relationships between tables. Unique IDs define the identity of a record. Any process that depends on stability over time, such as filters, reports, integrations, or upserts, must use the immutable *_ID field, never the *_KEY.
List of Analyze Direct Key Fields and Corresponding Unique ID Fields
The following table maps Surrogate Key fields to their guaranteed Unique Identifier equivalents.
| Table Name | Surrogate Key | Unique Identifier Fields |
| DIM_ASSESSMENT_QUESTION | QUESTION_KEY | QUESTION_ID |
| DIM_ASSESSMENT_QUESTION_OPTION | QUESTION_OPTION_KEY | QUESTION_OPTION_ID |
| DIM_CATEGORY | CATEGORY_KEY | CATEGORY_ID |
| DIM_CHAPTER | CHAPTER_KEY | CHAPTER_ID |
| DIM_CLASS | CLASS_KEY | CLASS_ID |
| DIM_COMPETENCY_CATEGORY | COMPETENCY_CATEGORY_KEY | COMPETENCY_CATEGORY_ID |
| DIM_COMPETENCY_DEFINITION | COMPETENCY_DEFINITION_KEY | COMPETENCY_DEFINITION_ID |
| DIM_COUPON | COUPON_KEY | COUPON_ID |
| DIM_COURSE | COURSE_KEY | COURSE_ID |
| DIM_COURSE_BUNDLE | COURSE_BUNDLE_KEY | COURSE_BUNDLE_ID |
| DIM_COURSE_SKILL | SKILL_KEY | SKILL_ID |
| DIM_COURSE_UPLOAD_DEFINITION | COURSE_UPLOAD_DEFINITION_KEY | COURSE_UPLOAD_DEFINITION_ID |
| DIM_CURRICULUM | CURRICULUM_KEY | CURRICULUM_ID |
| DIM_CURRICULUM_GROUP | CURRICULUM_GROUP_KEY | CURRICULUM_GROUP_ID |
| DIM_DEPARTMENT | DEPARTMENT_KEY | DEPARTMENT_ID |
| DIM_DIRECT_INDIRECT_MANAGER | MANAGER_KEY | MANAGER_ID |
| DIM_ENROLLMENT_KEY | ENROLLMENT_KEY_KEY | ENROLLMENT_KEY_ID |
| DIM_EVALUATION_QUESTION | QUESTION_KEY | QUESTION_ID |
| DIM_EXTENSION_PRICE | EXTENSION_PRICE_KEY | EXTENSION_PRICE_ID |
| DIM_EXTERNAL_TRAINING_TEMPLATE | EXTERNAL_TRAINING_TEMPLATE_KEY | EXTERNAL_TRAINING_TEMPLATE_ID |
| DIM_GROUP | GROUP_KEY | GROUP_ID |
| DIM_JOB_ROLE | JOB_ROLE_KEY | JOB_ROLE_ID |
| DIM_LESSON | LESSON_KEY | LESSON_ID |
| DIM_PRICE | PRICE_KEY | PRICE_ID |
| DIM_ROLE | ROLE_KEY | ROLE_ID |
| DIM_SESSION | SESSION_KEY | SESSION_ID |
| DIM_TAG | TAG_KEY | TAG_ID |
| DIM_USER | USER_KEY | USER_ID |
| DIM_VENUE | VENUE_KEY | VENUE_ID |
| FACT_ATTEMPT | ATTEMPT_KEY | ATTEMPT_ID |
| FACT_ATTEMPT_SUMMARY | LESSON_ENROLLMENT_KEY | LESSON_ENROLLMENT_ID |
| FACT_ATTENDANCE | ATTENDANCE_KEY | ATTENDANCE_ID |
| FACT_AWARDED_CERTIFICATE | AWARDED_CERTIFICATE_KEY | CERTIFICATE_ID |
| FACT_CHECKLIST_REVIEW | CHECKLIST_REVIEW_KEY | REVIEW_ID |
| FACT_CHECKLIST_REVIEW_STEP | CHECKLIST_REVIEW_STEP_KEY | REVIEW_STEP_ID |
| FACT_COURSE_BUNDLE_ENROLLMENT | COURSE_BUNDLE_ENROLLMENT_KEY | COURSE_BUNDLE_ENROLLMENT_ID |
| FACT_COURSE_ENROLLMENT | COURSE_ENROLLMENT_KEY | COURSE_ENROLLMENT_ID |
| FACT_CURRICULUM_ENROLLMENT | CURRICULUM_ENROLLMENT_KEY | CURRICULUM_ENROLLMENT_ID |
| FACT_EXTERNAL_TRAINING_SUBMISSION | EXTERNAL_TRAINING_SUBMISSION_KEY | SUBMISSION_ID |
| FACT_LESSON_ENROLLMENT | LESSON_ENROLLMENT_KEY | LESSON_ENROLLMENT_ID |
| FACT_LOGIN_SUMMARY | USER_KEY | USER_ID |
| FACT_QUESTION_ANSWER | ASSESSMENT_ANSWER_KEY | ASSESSMENT_ANSWER_ID |
| FACT_QUESTION_RESULT | ASSESSMENT_ACTIVITY_KEY | ASSESSMENT_ACTIVITY_ID |
| FACT_SELF_ASSESSMENT | SELF_ASSESSMENT_KEY | SELF_ASSESSMENT_ID |
| FACT_SESSION_ENROLLMENT | SESSION_ENROLLMENT_KEY | SESSION_ENROLLMENT_ID |
| FACT_SHOPPING_CART_TRANSACTION | SHOPPING_CART_TRANSACTION_KEY | SHOPPING_CART_TRANSACTION_ID |
Comments
Article is closed for comments.