Removing duplicated serial numbers in serial table

BK14
Mega Guru

ServiceNow has created numerous duplicated records in Serial table where Serial number + Serial type + CI (combined) are the same. We need to retain the latest record and remove the rest of the duplicated records. For instance in this chart, we want to keep the records in row 1 and 7, and remove the rest.

find_real_file.png

we will need 2 scripts, the first one to identify the dups and prints the records so we can analyze the data and the second one is to delete them. Please advise if you can provide the scripts to us.

Thank you very much for your help,

bk

1 ACCEPTED SOLUTION

BK14
Mega Guru

Thank you Rahul for the script. I also got another script from a former colleague that works too. Here is the script:

 

// *********************************** SETUP ****************************************************************************************************************

 

var dryRun = true; // SET THIS TO FALSE TO ACTUALLY DELETE RECORDS

var tableName = 'cmdb_serial_number'; // TARGET TABLE

var encodedQuery = ‘cmdb_ci'=; // APPLY ANY FILTER CONDITIONS HERE

var identifierFields = cmdb_ci.name='XXXXXXX’; //USED TO IDENTIFY THE DUPLICATES

var batch = 100; //SETS THE LIMIT FOR HOW MANY RECORDS ARE IN THE GLIDERECORD

 

// **********************************************************************************************************************************************************

 

var identifiers = identifierFields.split(','); //split up the groupby fields, we'll use this one later

var agg = new GlideAggregate(tableName);

agg.addQuery(encodedQuery);

agg.setLimit(batch);

 

// ADD THE COMBINATION OF UNIQUE IDENTIFIERS HERE

for(var i = 0; i < identifiers.length; i++) {

agg.groupBy(identifiers[i]);

}

 

// DON'T BOTHER READING ANY RECORDS THAT AREN'T DUPLICATE

agg.addAggregate('COUNT');

agg.addHaving('COUNT','>','1'); // only where 1 or more duplicates exist

agg.query();

 

// AT THIS POINT WE ONLY HAVE DUPLICATE RECORDSETS (WHERE THERE IS MORE THAN ONE RECORD WITH THE SAME IDENTIFYING FIELDS)

// NOW LOOP THROUGH ALL OF THOSE RECORDSETS, KEEPING ONLY THE OLDEST RECORD AND DELETING THE REST

var resultString = '\nUnique Set\tRecord to keep\tRecord(s) to delete\n';  // In order to avoid using many gs.print() statements we simply add all the results to a string and display them at the end.

var resultCount = 0; //Count the duplicates

while(agg.next()) {

resultString += getSetDetailsString(agg); //log the set that brought us here

var dup = new GlideRecord(tableName);

dup.addQuery(encodedQuery);

dup.setLimit(batch);

 

//get the records that match the set

for(var i = 0; i < identifiers.length; i++) {

dup.addQuery(identifiers[i],agg[identifiers[i]]);

 }

 

// order by date ascending. the first record is the oldest and the one we want to preserve. Change for 'orderByDesc' to preserve the newest record and remove the rest

dup.orderBy('sys_created_on');

dup.query();

 

// skip the first record (original) and log it

dup.next();

resultString += (dup.sys_created_on + ' - '+ dup.sys_id + '\t');

 

// loop through and delete the remaining records for this set. Only deletes if dryRun = false

while(dup.next()) {

resultString += (dup.sys_created_on + ' - '+ dup.sys_id + ', ');

resultCount++;

if(!dryRun) { //CAREFUL

dup.setWorkflow(false);

dup.deleteRecord();

}

}

resultString += '\n';

}

 

//Display results in TAB SEPARATED FORMAT

gs.print('Duplicate count: ' + resultCount);

gs.print(resultString);

//helper method to dynamically create the SET string for logging

function getSetDetailsString(gRecord) {

var returnString = '(';

for(var i = 0; i < identifiers.length; i++) {

returnString += identifiers[i] + ': ' + gRecord[identifiers[i]] + ', ';

}

returnString += ')\t';

return returnString;

 

View solution in original post

5 REPLIES 5

bammar
Kilo Sage
Kilo Sage

https://community.servicenow.com/community?id=community_question&sys_id=39868725db1cdbc01dcaf3231f9619c8

Rahul Priyadars
Giga Sage
Giga Sage

You can first identify the duplicates using below Script. Once its identified you can easily delete them.

 Find Duplicate CIs by Serial Number

gs.print(getDuplicates('cmdb_ci_server','serial_number'));
function getDuplicates(tablename,val) {
var dupRecords = [];
var gaDupCheck = new GlideAggregate(tablename);
gaDupCheck.addQuery('active','true');
gaDupCheck.addAggregate('COUNT',val);
gaDupCheck.addNotNullQuery(val);
gaDupCheck.groupBy(val);
gaDupCheck.addHaving('COUNT', '>', 1);
gaDupCheck.query();
while (gaDupCheck.next()) {
dupRecords.push(gaDupCheck[val].toString());  
}
return dupRecords;
}

You can customize it as per need.

Now for Deletion Mark any Field in above table as DeleteFlag = Yes
Then you can query all these records where Delete=Yes and delete it .
var snnod = new GlideRecord('cmdb_ci_server'); //Table Name
snnod.addQuery("deleteflag","true"); // Filter
snnod.query();
while(snnod.next()){
snnod.setWorkflow(false);
count++;
snnod.deleteRecord(); // Delete records
}
gs.print('No. of records deleted = '+count);

Hope this helps.

Regards
RP
 

Hi Rahul,

Thank you for the script. Unfortunately this script will identify all "legit" and "not legit" duplicates in Serial number table. Legit duplicates are that the same serial numbers having different serial number types (uuid, chassis, physical etc). Non legit dups in Serial number table are those that we have multiple records for the same serial number that have the same serial type.

for instance in my examples above, Serial abc123 is duplicated only if the type is also the same. 

So Serial abc123 with serial type of Chassis is not considered a duplicate with Serial = abc123 and type = system. They both can and should exist.

Unfortunately I am not experienced in scripting but I would like to modify your scrip to implement this logic to find only the "not legit" duplicates where serial number and serial number type (combined) are duplicated.

 

Thank you

bk

what is the volume you have in Serial No Table?

You can export records in XLS (with Sys_Id column) and then Play with data in XLS.

now fetch the records from XLS .

Fire the Query based on SYS_ID on Serial No Table - SYS_ID is oneof (YOUR LIST).

Then you can delete from GUI.

Regards

RP