Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

How to investigate where the table References used Before Deleting a Custom Table in ServiceNow

KrushnakumaT
Tera Guru
To optimize subscription costs, we have a requirement to delete a custom table in ServiceNow. Before proceeding, we need to ensure that the table or its records are not referenced anywhere in the platform, such as in fields, scripts, choice lists, or other configurations. Is there a way to check these references using a background script or any other method?
 
Thanks in adnvaced!!
2 REPLIES 2

Ankur Bawiskar
Tera Patron
Tera Patron

@KrushnakumaT 

there is no direct OOTB way for this

things to check and find

-> dictionary references (reference field, glidelist field, document id field)

-> business rules, client scripts, UI actions, reports, ACLs, script includes, UI policies

-> workflow run script, flow trigger etc

-> script actions, email notifications, email script, scheduled job

I got this code from AI tool and used incident table for example, you can try to use that script and enhance

// Set this to your custom table name
var TABLE_NAME = 'incident';
var LIKE = '%' + TABLE_NAME + '%';

function log(msg) {
  gs.info(msg);
}

// 1) Dictionary: fields referencing or extending the table
log('=== Dictionary references to table or its fields ===');
var dict = new GlideRecord('sys_dictionary');
dict.addEncodedQuery('name=' + TABLE_NAME + '^ORreference=' + TABLE_NAME + '^ORinternal_typeLIKE' + TABLE_NAME);
dict.query();
while (dict.next()) {
  log(dict.getValue('sys_id') + ' | ' + dict.getValue('name') + '.' + dict.getValue('element') + ' | type=' + dict.getValue('internal_type') + ' | ref=' + dict.getValue('reference'));
}

// 2) Business rules, client scripts, UI policies, etc. containing the table name
var configTables = [
  'sys_script',              // Business Rules
  'sys_script_client',       // Client Scripts
  'sys_ui_policy',           // UI Policies
  'sys_script_include',      // Script Includes
  'sysauto_script',          // Scheduled Scripts
  'wf_workflow',             // Legacy Workflows
  'sys_flow_context',        // Flow Designer (runtime refs)
  'sys_hub_flow',            // Flow definitions
  'sys_report',              // Reports
  'sys_security_acl',        // ACLs
  'sys_ui_action',           // UI Actions
  'sys_ui_page',             // UI Pages / Jelly
  'sys_web_service',         // Scripted Web Services
  'sys_ws_operation',        // SOAP ops
  'sys_rest_message'         // Outbound REST messages
];

function queryTableForString(table, fieldList) {
  var gr = new GlideRecord(table);
  var qc = gr.addQuery('sys_id', '!=', ''); // placeholder
  qc.addOrCondition('name', 'CONTAINS', TABLE_NAME);
  var fields = fieldList || ['script', 'condition', 'filter', 'operation', 'description', 'definition', 'template', 'url', 'rest_endpoint'];
  for (var i = 0; i < fields.length; i++) {
    qc.addOrCondition(fields[i], 'CONTAINS', TABLE_NAME);
  }
  gr.query();
  while (gr.next()) {
    log('[' + table + '] ' + gr.getDisplayValue() + ' (' + gr.getValue('sys_id') + ')');
  }
}

log('=== Scripted/config references containing table name ===');
for (var i = 0; i < configTables.length; i++) {
  queryTableForString(configTables[i]);
}

💡 If my response helped, please mark it as correct and close the thread 🔒— this helps future readers find the solution faster! 🙏

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

debendudas
Mega Sage
Mega Sage

Hi @KrushnakumaT ,

There are no OOTB script present for this.

I've created a comprehensive Fix Script that checks all possible references to a custom table. 

 

#Note: Please test and review the script before using it.

/*
 * INSTRUCTIONS:
 * 1. Replace 'u_your_custom_table' with your actual table name
 * 2. Run the script
 * 3. Review the output for any references
 * 4. Only delete the table if no critical references are found
 */

(function checkTableReferences() {
    
    // ===== CONFIGURATION =====
    var tableName = 'u_your_custom_table'; // CHANGE THIS to your table name
    
    // ===== INITIALIZATION =====
    var results = {
        tableName: tableName,
        totalReferences: 0,
        references: {}
    };
    
    gs.print('\n========================================');
    gs.print('TABLE REFERENCE CHECKER');
    gs.print('Checking references for: ' + tableName);
    gs.print('========================================\n');
    
    // ===== 1. CHECK DICTIONARY ENTRIES (Fields referencing this table) =====
    gs.print('1. Checking Dictionary Entries (Reference Fields)...');
    var dictGr = new GlideRecord('sys_dictionary');
    dictGr.addQuery('reference', tableName);
    dictGr.query();
    
    var dictResults = [];
    while (dictGr.next()) {
        dictResults.push({
            table: dictGr.name.toString(),
            field: dictGr.element.toString(),
            label: dictGr.column_label.toString(),
            sys_id: dictGr.sys_id.toString()
        });
    }
    
    if (dictResults.length > 0) {
        results.references.dictionaryEntries = dictResults;
        results.totalReferences += dictResults.length;
        gs.print('   FOUND ' + dictResults.length + ' reference field(s):');
        for (var i = 0; i < dictResults.length; i++) {
            gs.print('   - ' + dictResults[i].table + '.' + dictResults[i].field + ' (' + dictResults[i].label + ')');
        }
    } else {
        gs.print('   No reference fields found.');
    }
    
    // ===== 2. CHECK BUSINESS RULES =====
    gs.print('\n2. Checking Business Rules...');
    var brGr = new GlideRecord('sys_script');
    brGr.addQuery('collection', tableName)
        .addOrCondition('script', 'CONTAINS', tableName);
    brGr.query();
    
    var brResults = [];
    while (brGr.next()) {
        brResults.push({
            name: brGr.name.toString(),
            table: brGr.collection.toString(),
            when: brGr.when.toString(),
            active: brGr.active.toString(),
            sys_id: brGr.sys_id.toString()
        });
    }
    
    if (brResults.length > 0) {
        results.references.businessRules = brResults;
        results.totalReferences += brResults.length;
        gs.print('   FOUND ' + brResults.length + ' business rule(s):');
        for (var j = 0; j < brResults.length; j++) {
            gs.print('   - ' + brResults[j].name + ' (Table: ' + brResults[j].table + ')');
        }
    } else {
        gs.print('   No business rules found.');
    }
    
    // ===== 3. CHECK CLIENT SCRIPTS =====
    gs.print('\n3. Checking Client Scripts...');
    var csGr = new GlideRecord('sys_script_client');
    csGr.addQuery('table', tableName)
        .addOrCondition('script', 'CONTAINS', tableName);
    csGr.query();
    
    var csResults = [];
    while (csGr.next()) {
        csResults.push({
            name: csGr.name.toString(),
            table: csGr.table.toString(),
            type: csGr.type.toString(),
            active: csGr.active.toString(),
            sys_id: csGr.sys_id.toString()
        });
    }
    
    if (csResults.length > 0) {
        results.references.clientScripts = csResults;
        results.totalReferences += csResults.length;
        gs.print('   FOUND ' + csResults.length + ' client script(s):');
        for (var k = 0; k < csResults.length; k++) {
            gs.print('   - ' + csResults[k].name + ' (' + csResults[k].type + ')');
        }
    } else {
        gs.print('   No client scripts found.');
    }
    
    // ===== 4. CHECK UI POLICIES =====
    gs.print('\n4. Checking UI Policies...');
    var uiPolicyGr = new GlideRecord('sys_ui_policy');
    uiPolicyGr.addQuery('table', tableName);
    uiPolicyGr.query();
    
    var uiPolicyResults = [];
    while (uiPolicyGr.next()) {
        uiPolicyResults.push({
            short_description: uiPolicyGr.short_description.toString(),
            table: uiPolicyGr.table.toString(),
            active: uiPolicyGr.active.toString(),
            sys_id: uiPolicyGr.sys_id.toString()
        });
    }
    
    if (uiPolicyResults.length > 0) {
        results.references.uiPolicies = uiPolicyResults;
        results.totalReferences += uiPolicyResults.length;
        gs.print('   FOUND ' + uiPolicyResults.length + ' UI policy(ies):');
        for (var l = 0; l < uiPolicyResults.length; l++) {
            gs.print('   - ' + uiPolicyResults[l].short_description);
        }
    } else {
        gs.print('   No UI policies found.');
    }
    
    // ===== 5. CHECK UI ACTIONS =====
    gs.print('\n5. Checking UI Actions...');
    var uiActionGr = new GlideRecord('sys_ui_action');
    uiActionGr.addQuery('table', tableName)
        .addOrCondition('script', 'CONTAINS', tableName);
    uiActionGr.query();
    
    var uiActionResults = [];
    while (uiActionGr.next()) {
        uiActionResults.push({
            name: uiActionGr.name.toString(),
            table: uiActionGr.table.toString(),
            action_name: uiActionGr.action_name.toString(),
            active: uiActionGr.active.toString(),
            sys_id: uiActionGr.sys_id.toString()
        });
    }
    
    if (uiActionResults.length > 0) {
        results.references.uiActions = uiActionResults;
        results.totalReferences += uiActionResults.length;
        gs.print('   FOUND ' + uiActionResults.length + ' UI action(s):');
        for (var m = 0; m < uiActionResults.length; m++) {
            gs.print('   - ' + uiActionResults[m].name);
        }
    } else {
        gs.print('   No UI actions found.');
    }
    
    // ===== 6. CHECK ACL RULES =====
    gs.print('\n6. Checking ACL Rules...');
    var aclGr = new GlideRecord('sys_security_acl');
    aclGr.addQuery('name', 'CONTAINS', tableName);
    aclGr.query();
    
    var aclResults = [];
    while (aclGr.next()) {
        aclResults.push({
            name: aclGr.name.toString(),
            operation: aclGr.operation.toString(),
            active: aclGr.active.toString(),
            sys_id: aclGr.sys_id.toString()
        });
    }
    
    if (aclResults.length > 0) {
        results.references.aclRules = aclResults;
        results.totalReferences += aclResults.length;
        gs.print('   FOUND ' + aclResults.length + ' ACL rule(s):');
        for (var n = 0; n < aclResults.length; n++) {
            gs.print('   - ' + aclResults[n].name + ' (' + aclResults[n].operation + ')');
        }
    } else {
        gs.print('   No ACL rules found.');
    }
    
    // ===== 7. CHECK WORKFLOWS =====
    gs.print('\n7. Checking Workflows...');
    var wfGr = new GlideRecord('wf_workflow');
    wfGr.addQuery('table', tableName);
    wfGr.query();
    
    var wfResults = [];
    while (wfGr.next()) {
        wfResults.push({
            name: wfGr.name.toString(),
            table: wfGr.table.toString(),
            active: wfGr.active.toString(),
            sys_id: wfGr.sys_id.toString()
        });
    }
    
    if (wfResults.length > 0) {
        results.references.workflows = wfResults;
        results.totalReferences += wfResults.length;
        gs.print('   FOUND ' + wfResults.length + ' workflow(s):');
        for (var o = 0; o < wfResults.length; o++) {
            gs.print('   - ' + wfResults[o].name);
        }
    } else {
        gs.print('   No workflows found.');
    }
    
    // ===== 8. CHECK SCRIPT INCLUDES =====
    gs.print('\n8. Checking Script Includes...');
    var siGr = new GlideRecord('sys_script_include');
    siGr.addQuery('script', 'CONTAINS', tableName);
    siGr.query();
    
    var siResults = [];
    while (siGr.next()) {
        siResults.push({
            name: siGr.name.toString(),
            api_name: siGr.api_name.toString(),
            active: siGr.active.toString(),
            sys_id: siGr.sys_id.toString()
        });
    }
    
    if (siResults.length > 0) {
        results.references.scriptIncludes = siResults;
        results.totalReferences += siResults.length;
        gs.print('   FOUND ' + siResults.length + ' script include(s):');
        for (var p = 0; p < siResults.length; p++) {
            gs.print('   - ' + siResults[p].name);
        }
    } else {
        gs.print('   No script includes found.');
    }
    
    // ===== 9. CHECK SCHEDULED JOBS =====
    gs.print('\n9. Checking Scheduled Jobs...');
    var schedGr = new GlideRecord('sysauto_script');
    schedGr.addQuery('script', 'CONTAINS', tableName);
    schedGr.query();
    
    var schedResults = [];
    while (schedGr.next()) {
        schedResults.push({
            name: schedGr.name.toString(),
            active: schedGr.active.toString(),
            sys_id: schedGr.sys_id.toString()
        });
    }
    
    if (schedResults.length > 0) {
        results.references.scheduledJobs = schedResults;
        results.totalReferences += schedResults.length;
        gs.print('   FOUND ' + schedResults.length + ' scheduled job(s):');
        for (var q = 0; q < schedResults.length; q++) {
            gs.print('   - ' + schedResults[q].name);
        }
    } else {
        gs.print('   No scheduled jobs found.');
    }
    
    // ===== 10. CHECK REPORTS =====
    gs.print('\n10. Checking Reports...');
    var reportGr = new GlideRecord('sys_report');
    reportGr.addQuery('table', tableName);
    reportGr.query();
    
    var reportResults = [];
    while (reportGr.next()) {
        reportResults.push({
            title: reportGr.title.toString(),
            table: reportGr.table.toString(),
            sys_id: reportGr.sys_id.toString()
        });
    }
    
    if (reportResults.length > 0) {
        results.references.reports = reportResults;
        results.totalReferences += reportResults.length;
        gs.print('   FOUND ' + reportResults.length + ' report(s):');
        for (var r = 0; r < reportResults.length; r++) {
            gs.print('   - ' + reportResults[r].title);
        }
    } else {
        gs.print('   No reports found.');
    }
    
    // ===== 11. CHECK RECORD COUNT =====
    gs.print('\n11. Checking Record Count...');
    var recordGr = new GlideRecord(tableName);
    if (recordGr.isValid()) {
        recordGr.query();
        var recordCount = recordGr.getRowCount();
        results.recordCount = recordCount;
        gs.print('   Table contains ' + recordCount + ' record(s).');
    } else {
        gs.print('   ERROR: Table "' + tableName + '" does not exist or is invalid.');
        results.error = 'Table does not exist or is invalid';
    }
    
    // ===== FINAL SUMMARY =====
    gs.print('\n========================================');
    gs.print('SUMMARY');
    gs.print('========================================');
    gs.print('Table: ' + tableName);
    gs.print('Total References Found: ' + results.totalReferences);
    gs.print('Record Count: ' + (results.recordCount || 'N/A'));
    
    if (results.totalReferences === 0 && (!results.recordCount || results.recordCount === 0)) {
        gs.print('\n✓ SAFE TO DELETE: No references or records found.');
    } else if (results.totalReferences === 0 && results.recordCount > 0) {
        gs.print('\n⚠ WARNING: No references found, but table contains ' + results.recordCount + ' record(s).');
        gs.print('  Consider backing up data before deletion.');
    } else {
        gs.print('\n✗ NOT SAFE TO DELETE: References found in the system.');
        gs.print('  Review and remove dependencies before deleting the table.');
    }
    
    gs.print('========================================\n');
    
    // Return results object for programmatic access if needed
    return results;
    
})();

 

This Script Checks the below:

- Dictionary Entries
- Business Rules 
- Client Scripts
- UI Policies 
- UI Actions 
- ACL Rules
- Workflows
- Script Includes
- Scheduled Jobs
- Reports
- Record Count

 

Output Interpretation:

- SAFE TO DELETE: No references or records found
- WARNING: No references but contains data (backup recommended)
- NOT SAFE: References found - must be removed first

 

Best Practices:

- Run this in a sub-production environment first
- Document all found references
- Create a backup of the table data before deletion

 

If this answer helped you, please mark it as the accepted answer and mark it as helpful 👍.