Table Inheritance in SQL: A Comprehensive Guide | [Your Brand/Site Name]




Mastering Table Inheritance in ServiceNow: A Deep Dive for Developers


Mastering Table Inheritance in ServiceNow: A Deep Dive for Developers

In the intricate world of ServiceNow development, understanding how data is structured and managed is paramount. One of the most fundamental yet powerful concepts is table inheritance. It allows us to build robust and scalable solutions by leveraging existing structures, promoting code reusability, and ensuring data integrity. This article will unravel the complexities of table inheritance, providing practical insights, real-world examples, and crucial tips for both budding and seasoned ServiceNow professionals.

The Core Concept: What is Table Inheritance?

At its heart, table inheritance in ServiceNow is akin to biological inheritance – a child inherits traits from its parent. In the context of databases, a child table inherits all the columns (fields) from its parent table. This means you don’t need to redefine common fields like ‘Number’, ‘Created’, ‘Updated’, ‘Created By’, or ‘Updated By’ in every new table you create. They are automatically present because they reside in the parent table.

How it Works Under the Hood: The ‘sys_class_name’ Field

When you extend a table, ServiceNow doesn’t create duplicate system fields (like sys_id, sys_created_on, etc.) in the child table. These are magically handled by the parent. Instead, a special field called sys_class_name is introduced in the parent table. This field stores the sys_id of the actual table record that the current row belongs to. For instance, if you have a ‘Problem’ table that extends ‘Task’, and a specific record is a ‘Problem’, its sys_class_name will point to the ‘Problem’ table record.

This is a crucial point for understanding how ServiceNow differentiates between records from different child tables that share a common parent. Even if a table extends multiple tables (which is rare and generally discouraged due to complexity), it will still have only one sys_class_name field pointing to its ultimate “class” or specific type.

Key Takeaway: Extending a table means inheriting fields. The sys_class_name field in the parent table is the mechanism that allows ServiceNow to track the specific child table a record belongs to.

Benefits of Using Table Inheritance

  • Reduced Redundancy: Avoids repeating common fields across multiple tables.
  • Data Consistency: Ensures common data attributes are defined and managed in a single place.
  • Simplified Development: Faster creation of new tables by starting from an existing structure.
  • Enhanced Maintainability: Changes to inherited fields only need to be made in the parent table.
  • Polymorphism: Enables treating records from different child tables uniformly through their common parent. Think of a “Task” list that can display Incidents, Problems, Changes, etc.

When to Extend: Practical Scenarios

The decision to extend a table usually arises when you need to create a new type of record that shares many common attributes with an existing table but also requires unique fields or behaviors.

Common Extension Scenarios:

  • ITSM Modules: Incidents, Problems, Changes, and Service Requests all extend the base ‘Task’ table. They share common fields like ‘Short Description’, ‘Assigned To’, ‘Assignment Group’, ‘State’, and ‘Number’, but each has its own specific fields (e.g., ‘Problem ID’, ‘Affected CIs’ for Problems, ‘Risk’ for Changes).
  • User Management: ‘Employee’ might extend ‘User’ to add company-specific attributes.
  • Asset Management: ‘Hardware Asset’ and ‘Software Asset’ could extend a common ‘Asset’ table.

Developer’s Tip: Before creating a new table from scratch, always ask yourself: “Does a similar table already exist? Can I extend it?” This simple question can save you significant development time and effort.

Deep Dive into Related Concepts: Dictionary Overrides

While inheritance brings powerful benefits, there are times when you need to slightly alter the behavior or properties of an inherited field in a child table. This is where Dictionary Overrides come into play.

What are Dictionary Overrides?

A dictionary override allows you to modify the attributes of a field in a child table without affecting its definition in the parent table. Essentially, you’re creating a specific version of an inherited field for your child table.

Example: The ‘Priority’ field might have a default value of ‘4 – Low’ in the parent ‘Task’ table. However, for the ‘Incident’ table, you might want the default priority to be ‘2 – Medium’. A dictionary override on the ‘Priority’ field within the ‘Incident’ table can achieve this.

Properties You Can Override:

You can override a wide range of properties defined in the parent table’s dictionary entry. Some of the most common ones include:

  • Default value: Setting a different default value for the field in the child table.
  • Mandatory: Making an inherited field mandatory (or optional if it was mandatory in the parent).
  • Read-only: Making an inherited field read-only.
  • Max length: Changing the maximum allowed length for text fields.
  • Display: Marking a field to be displayed on list views or other areas.
  • Reference specification: Altering reference qualifiers or cascade rules for reference fields.
  • Auto-increment: Modifying auto-increment behavior.

Creating a Dictionary Override:

  1. Navigate to System Definition > Dictionary.
  2. Find the dictionary entry for the field in the child table.
  3. In the dictionary entry form, you’ll see a related list called “Overrides”. Click “New”.
  4. Select the parent table and configure the desired properties for the field in this specific child table.

Troubleshooting Dictionary Overrides: If a change you expect to see in a child table’s field isn’t appearing, double-check that you’ve created the override on the correct child table and that the override is targeting the correct field. Also, ensure no other mechanism (like UI Policies or Client Scripts) is overriding the behavior.

Controlling Field Behavior: UI Policies and Data Policies

Beyond the structural aspects of inheritance, developers often need to dynamically control how fields behave on a form based on certain conditions. This is where UI Policies and Data Policies shine.

UI Policies: Client-Side Form Manipulation

What are UI Policies?

UI Policies are powerful client-side tools used to dynamically change form behavior without writing JavaScript code directly into client scripts (though they can invoke scripts!). They are excellent for making fields mandatory, read-only, visible/hidden, or setting their default values based on specific conditions evaluated on the browser.

Key UI Policy Properties:

  • Global checkbox: If checked, the UI Policy applies to all views. If unchecked, you specify the views where it should run. This is crucial for ensuring consistent form behavior across different user interfaces.
  • Reverse if false: A godsend for simplifying logic! If checked, when the UI Policy’s conditions evaluate to false, all the actions defined in the UI Policy are reversed. For example, if a field is made mandatory when the condition is true, checking “Reverse if false” means it will become optional again when the condition is false.
  • On Load checkbox: When selected, the UI Policy’s actions are executed as soon as the form loads. If unchecked, the UI Policy’s actions are only triggered when a field value changes that meets the UI Policy’s conditions.
  • Inherit checkbox: This is where UI Policies interact with table inheritance. If checked on a UI Policy defined on a parent table, that UI Policy will also be applied to all child tables that extend it. This is a fantastic way to enforce consistent form logic across an inheritance hierarchy.

Can you write scripts in UI Policies?

Absolutely! To run custom JavaScript, you need to enable the “Run scripts” checkbox on the UI Policy record. This will reveal the “UI Policy Script” tab where you can write “Execute if True” and “Execute if False” scripts. These scripts allow for more complex client-side manipulations that can’t be achieved through standard UI Policy actions.

Converting UI Policies to Data Policies:

ServiceNow offers a convenient “Convert to Data Policy” button on UI Policy records. This is useful when you want to enforce the same logic on both the client and server side. However, there are limitations.

Cases where UI Policy cannot be converted to Data Policy:

  • Controlling Data Visibility: UI Policies can hide fields, but Data Policies primarily focus on data integrity (mandatory, read-only).
  • Controlling Views: UI Policies can be view-specific, which is a presentation layer concern not directly handled by Data Policies.
  • Controlling Related Lists: UI Policies can show/hide related lists, a UI presentation aspect.
  • Controlling Scripts: If your UI Policy relies heavily on complex client-side scripts that have no direct server-side equivalent for data enforcement, conversion might not be straightforward or even possible without significant refactoring.

Interview Relevance: Be prepared to discuss the differences between UI Policies and Data Policies, their respective strengths, and when you’d choose one over the other. Understanding the “Global”, “Reverse if false”, and “Inherit” checkboxes for UI Policies is crucial.

Data Policies: Server and Client-Side Data Enforcement

What are Data Policies?

Data Policies are designed to enforce data integrity across all data sources, including client-side (forms) and server-side (integrations, imports, scripting). They make fields mandatory, read-only, or visible based on conditions, ensuring data consistency regardless of how it’s entered or modified.

Key Characteristics of Data Policies:

  • Dual Enforcement: They operate on both the client (for immediate user feedback) and the server (for absolute data integrity).
  • Focus on Data: Primarily concerned with making data correct and consistent.
  • No UI Manipulation (Directly): Unlike UI Policies, Data Policies don’t directly control the visibility of fields on a form or manipulate UI elements like related lists. Their goal is to control the data itself.

When to use which? Use UI Policies for dynamic form behavior (making fields appear/disappear, controlling read-only/mandatory based on user interaction on the form). Use Data Policies to enforce data integrity that must apply everywhere, regardless of the user interface or data source (e.g., ensuring a field is always mandatory when a certain condition is met, even if data is updated via an integration).

Working with Related Tables: Reference Qualifiers and Dependent Fields

Table inheritance often means you’re dealing with relationships between tables. Reference fields are how these relationships are represented. Reference Qualifiers and Dependent Fields are vital for controlling what data appears in these reference fields.

Reference Qualifiers: Filtering Referenced Data

What are Reference Qualifiers?

Reference Qualifiers are used to restrict the records that appear in a reference field or a list collector field. They act like `WHERE` clauses in SQL, filtering the available options to show only relevant data.

Types of Reference Qualifiers:

  1. Simple Reference Qualifier:

    This is the most straightforward type. You define a fixed query condition directly in the reference field’s dictionary entry. It’s ideal for static filtering.

    Example: To show only active users in a reference field pointing to the ‘User’ table, you’d set the condition to active=true.

    How to Use: In the dictionary entry for the reference field, go to the “Reference Specification” tab, and in the “Reference qual” field, enter your condition.

  2. Dynamic Reference Qualifier:

    This type uses a dynamically generated query that can adapt based on the context of the form. It leverages “Dynamic Filter Options” for more flexible filtering.

    Example: Displaying only incidents assigned to the current user’s assignment group. The query adapts based on the logged-in user and the context of the form.

    How to Use:

    1. Create a “Dynamic Filter Option” via System Definition > Dynamic Filter Options. Define your conditions here.
    2. In the reference field’s dictionary entry, select the “Dynamic” radio button for Reference qual and choose your created Dynamic Filter Option.
  3. Advanced Reference Qualifier (JavaScript Reference Qualifier):

    This is the most powerful type, allowing you to use custom JavaScript code to define complex queries. It’s perfect for filtering based on multiple conditions, current form values, or even server-side logic.

    Example: Filtering incidents to show only those assigned to the current user’s assignment group AND with a priority less than 3.

    How to Use: In the reference field’s dictionary entry, select “Advanced” for the Reference qual and enter your JavaScript code. For instance: javascript: 'assignment_group=' + g_form.getValue('assignment_group') + '^priority<3'; (This example assumes the current form has an 'assignment_group' field).

Differences:

  • Simple vs. Dynamic: Simple is static; Dynamic adapts based on predefined configurations.
  • Dynamic vs. Advanced: Dynamic uses pre-built "Dynamic Filter Options"; Advanced uses custom JavaScript for maximum flexibility.
  • Simple vs. Advanced: Simple is a direct query string; Advanced is executable JavaScript, allowing complex logic and interactions with the form.

Troubleshooting Reference Qualifiers: If your reference qualifier isn't working as expected, ensure the syntax is correct. For JavaScript qualifiers, use gs.debug() or gs.log() in a Script Include called by the qualifier to trace execution. Remember to check if the fields referenced in your qualifier actually exist on the form or are accessible in the script's context.

Dependent Fields: Cascading Select Lists

What is Dependent Value?

Dependent values are used to create cascaded dropdowns, where the choices available in one field (the dependent field) change based on the selection made in another field (the parent field).

How to Configure Dependent Values:

  1. Identify Parent and Dependent Fields: For example, 'Category' (parent) and 'Subcategory' (dependent).
  2. Configure the Parent Field: Ensure the parent field has a list of defined choices (e.g., Hardware, Software).
  3. Configure the Dependent Field:
    1. Go to the dictionary entry of the dependent field (e.g., Subcategory).
    2. In the "Reference Specification" tab, set the Dependent Field attribute to the parent field's name (e.g., category).
    3. Define the choices for the dependent field, linking them to specific parent field values. For instance, under the 'Subcategory' choices, you'd specify that if 'Category' is 'Hardware', the choices are 'Laptop', 'Desktop', etc.

Example: On an Incident form, when you select 'Hardware' as the Category, the Subcategory dropdown will automatically update to show only hardware-related subcategories like 'Printer', 'Laptop', 'Monitor'. If you change the Category to 'Software', the Subcategory choices will update to 'Operating System', 'Application', etc.

Developer's Tip: Dependent fields are a user-friendly way to guide users in making selections. They reduce errors by presenting only relevant options, improving the overall user experience.

Scripting Data Relationships: GlideRecord and Table Inheritance

When working with scripting, especially with GlideRecord, it's crucial to understand how table inheritance affects your queries and data manipulation.

Adding Roles to Users and Groups: A Practical Example

Referencing the provided snippets, let's look at how table inheritance is implicitly involved when managing user and group roles.

  • sys_user_has_role: This table stores the many-to-many relationship between users and roles. When you add a role to a user, a record is created here.
  • sys_group_has_role: Similarly, this table manages the relationship between groups and roles.

While these tables themselves might not directly extend a common "RoleAssignment" table in a typical inheritance pattern, they represent specific types of role assignments. The sys_user table and sys_user_group table are separate entities, and their relationship to roles is managed through these intermediary tables.

Scripting Example (from reference):


    // Add role to a user
    var userRole = new GlideRecord('sys_user_has_role');
    userRole.setValue('user', 'user_sys_id'); // Replace with actual user sys_id
    userRole.setValue('role', 'role_sys_id'); // Replace with actual role sys_id
    userRole.insert();

    // Add role to a group
    var grpRole = new GlideRecord('sys_group_has_role');
    grpRole.setValue('group', 'group_sys_id'); // Replace with actual group sys_id
    grpRole.setValue('role', 'role_sys_id'); // Replace with actual role sys_id
    grpRole.insert();
    

Managing Group Memberships

The sys_user_grmember table links users to groups. Again, this is a relational table, not necessarily a direct inheritance example, but it's a common scenario where understanding table relationships is key.

Scripting Examples (from reference):


    // Add a user to a group
    var grMem = new GlideRecord('sys_user_grmember');
    grMem.user = 'user_sys_id'; // Replace with actual user sys_id
    grMem.group = 'group_sys_id'; // Replace with actual group sys_id
    grMem.insert();

    // Remove a user from a group
    var grMem = new GlideRecord('sys_user_grmember');
    grMem.addQuery('user', 'user_sys_id'); // Replace with actual user sys_id
    grMem.addQuery('group', 'group_sys_id'); // Replace with actual group sys_id
    grMem.query();
    if (grMem.next()) {
        grMem.deleteRecord();
    }
    

Interview Relevance: You might be asked to write GlideRecord scripts for common tasks like managing roles or group memberships. Be comfortable with creating, querying, and deleting records in these junction tables.

Final Thoughts on Table Inheritance

Table inheritance is a cornerstone of efficient and scalable database design in ServiceNow. By understanding how to extend tables, leverage dictionary overrides, and orchestrate form behavior with UI and Data Policies, you can build sophisticated applications that are both powerful and maintainable.

Always remember to design with inheritance in mind. Start by identifying common data structures and behaviors. This proactive approach will lead to cleaner code, reduced development time, and a more robust ServiceNow instance. Happy coding!


Scroll to Top