Delete Unused Domains

15141
30
06-08-2015 11:50 AM
BlakeTerhune
MVP Regular Contributor

I created this script to help with some geodatabase house cleaning tasks. Maybe someone else will find it useful or have an idea to improve it.

import arcpy
import os

# Set workspace
myGDB = r"C:\temp\working.gdb"

# Get domains that are assigned to a field
domains_used = []
for dirpath, dirnames, filenames in arcpy.da.Walk(myGDB, datatype=["FeatureClass", "Table"]):
    for filename in filenames:
        print "Checking {}".format(os.path.join(dirpath, filename))
        try:
            ## Check for normal field domains
            for field in arcpy.ListFields(os.path.join(dirpath, filename)):
                if field.domain:
                    domains_used.append(field.domain)
            ## Check for domains used in a subtype field
            subtypes = arcpy.da.ListSubtypes(os.path.join(dirpath, filename))
            for stcode, stdict in subtypes.iteritems():
                if stdict["SubtypeField"] != u'':
                    for field, fieldvals in stdict["FieldValues"].iteritems():
                        if not fieldvals[1] is None:
                            domains_used.append(fieldvals[1].name)
        except Exception, err:
            print "Error:", err

# Get domains that exist in the geodatabase
domains_existing = [dom.name for dom in arcpy.da.ListDomains(myGDB)]

# Find existing domains that are not assigned to a field
domains_unused = set(domains_existing) ^ set(domains_used)
print "{} unused domains in {}".format(len(domains_unused), myGDB)
for domain in domains_unused:
    arcpy.DeleteDomain_management(myGDB, domain)
    print "{} deleted".format(domain)

python snippets

30 Replies
AndresCastillo
MVP Regular Contributor

I got it to work:

import arcpy  
import os  

#Slightly modified from Geonet thread by Blake Terhune titled 'Delete Unused Domains'  
# Set workspace  
arcpy.env.workspace = arcpy.GetParameterAsText(0)
 
  
# Get domains that are assigned to a field  
domains_used = []  
for dirpath, dirnames, filenames in arcpy.da.Walk(myGDB, datatype=["FeatureClass", "Table"]):  
    for filename in filenames:  
        print "Checking {}".format(os.path.join(dirpath, filename))  
        try:  
            ## Check for normal field domains  
            for field in arcpy.ListFields(os.path.join(dirpath, filename)):  
                if field.domain:  
                    domains_used.append(field.domain)  
            ## Check for domains used in a subtype field  
            subtypes = arcpy.da.ListSubtypes(os.path.join(dirpath, filename))  
            for stcode, stdict in subtypes.iteritems():  
                if stdict["SubtypeField"] != u'':  
                    for field, fieldvals in stdict["FieldValues"].iteritems():  
                        if not fieldvals[1] is None:  
                            domains_used.append(fieldvals[1].name)  
        except Exception, err:  
            print "Error:", err  
  
# Get domains that exist in the geodatabase  
domains_existing = [dom.name for dom in arcpy.da.ListDomains(myGDB)]  
  
# Find existing domains that are not assigned to a field  
domains_unused = set(domains_existing) ^ set(domains_used)  
print "{} unused domains in {}".format(len(domains_unused), myGDB) 
print domains_unused

print (domains_unused)
arcpy.AddMessage(domains_unused)
0 Kudos
BlakeTerhune
MVP Regular Contributor

Fixed in less than an hour! Love how just posting a problem can sometimes lead you to finding the answer yourself.

AndresCastillo
MVP Regular Contributor

Absolutely, me too!

Thank you for your awesome script!

JeremyLinley
New Contributor III

I cannot get this to work as a tool in a toolbox. I copied it exactly and it is giving me the error 'NameError: name 'myGDB' is not defined. I have set the tool parameters to Display Name: Workspace | Data Type: Workspace. What am I doing wrong? Below is my script:

import arcpy  
import os  

#Slightly modified from Geonet thread by Blake Terhune titled 'Delete Unused Domains'  
# Set workspace  
arcpy.env.workspace = arcpy.GetParameterAsText(0)
 
  
# Get domains that are assigned to a field  
domains_used = []  
for dirpath, dirnames, filenames in arcpy.da.Walk(myGDB, datatype=["FeatureClass", "Table"]):  
    for filename in filenames:  
        print "Checking {}".format(os.path.join(dirpath, filename))  
        try:  
            ## Check for normal field domains  
            for field in arcpy.ListFields(os.path.join(dirpath, filename)):  
                if field.domain:  
                    domains_used.append(field.domain)  
            ## Check for domains used in a subtype field  
            subtypes = arcpy.da.ListSubtypes(os.path.join(dirpath, filename))  
            for stcode, stdict in subtypes.iteritems():  
                if stdict["SubtypeField"] != u'':  
                    for field, fieldvals in stdict["FieldValues"].iteritems():  
                        if not fieldvals[1] is None:  
                            domains_used.append(fieldvals[1].name)  
        except Exception, err:  
            print "Error:", err  
  
# Get domains that exist in the geodatabase  
domains_existing = [dom.name for dom in arcpy.da.ListDomains(myGDB)]  
  
# Find existing domains that are not assigned to a field  
domains_unused = set(domains_existing) ^ set(domains_used)  
print "{} unused domains in {}".format(len(domains_unused), myGDB) 
print domains_unused

1 of 1 people found this helpful
    Helpful Yes  NoLike  0Reply
    • Andres Castillo

      I got it to work:

       

      import arcpy  
      import os  
      
      #Slightly modified from Geonet thread by Blake Terhune titled 'Delete Unused Domains'  
      # Set workspace  
      arcpy.env.workspace = arcpy.GetParameterAsText(0)
       
        
      # Get domains that are assigned to a field  
      domains_used = []  
      for dirpath, dirnames, filenames in arcpy.da.Walk(myGDB, datatype=["FeatureClass", "Table"]):  
          for filename in filenames:  
              print "Checking {}".format(os.path.join(dirpath, filename))  
              try:  
                  ## Check for normal field domains  
                  for field in arcpy.ListFields(os.path.join(dirpath, filename)):  
                      if field.domain:  
                          domains_used.append(field.domain)  
                  ## Check for domains used in a subtype field  
                  subtypes = arcpy.da.ListSubtypes(os.path.join(dirpath, filename))  
                  for stcode, stdict in subtypes.iteritems():  
                      if stdict["SubtypeField"] != u'':  
                          for field, fieldvals in stdict["FieldValues"].iteritems():  
                              if not fieldvals[1] is None:  
                                  domains_used.append(fieldvals[1].name)  
              except Exception, err:  
                  print "Error:", err  
        
      # Get domains that exist in the geodatabase  
      domains_existing = [dom.name for dom in arcpy.da.ListDomains(myGDB)]  
        
      # Find existing domains that are not assigned to a field  
      domains_unused = set(domains_existing) ^ set(domains_used)  
      print "{} unused domains in {}".format(len(domains_unused), myGDB) 
      print domains_unused
      
      print (domains_unused)
      arcpy.AddMessage(domains_unused)
    0 Kudos
    BlakeTerhune
    MVP Regular Contributor

    I'm not sure exactly what Andres Castillo‌ changed to get his working, but it looks like the myGDB variable is undefined. Try assigning it on line 6 of your script like

    myGDB = arcpy.GetParameterAsText(0)
    AndresCastillo
    MVP Regular Contributor

    Hi Jeremy,

    as far as I can remember, Blake Terhune is right about what I changed.

    Did this work for you?

    0 Kudos
    RhettZufelt
    MVP Frequent Contributor

    running this in 10.2.1 (the GitHub version) I noticed that it see's SDE rasters as FeatureClass which errors out trying to get domain info.

    I had to limit the da.walk with this to get past the raster dataset(s) issues.

    for dirpath, dirnames, filenames in arcpy.da.Walk(myGDB, datatype=["FeatureClass", "Table"], type=['Polygon', 'Polyline','Point']):  

    R_

    MicahBabinski
    Occasional Contributor III

    Outstanding, Blake Terhune! I saw you had provided a good answer to a question I posted a few years back about unused domains that included a link to this script. I'm getting it set up to work in my environment now. Thanks!

    JanTeisinger
    New Contributor II

    I understand this is an older thread, but for those folks who would prefer to simply list unused domains without running arcpy, you can use the following SQL query that I have put together:

    WITH SUBDomainsAndFields
    as
    (
    		SELECT distinct
    		  UPPER(PARSENAME(ClassDefs.Name,1)) AS "ClassName",
    		  fieldDef.value('FieldName[1]', 'nvarchar(max)') AS "FieldName",
    		  fieldDef.value('(../../SubtypeName)[1]', 'nvarchar(max)') AS "SubtypeName",
    		  fieldDef.value('DomainName[1]', 'nvarchar(max)') AS "DomainName"
    		FROM
    		  GDB_ITEMS AS ClassDefs
    		CROSS APPLY
    		   Definition.nodes('/*/Subtypes/Subtype/FieldInfos/SubtypeFieldInfo') AS FieldDefs(fieldDef)
    
    		union all
    
    		   SELECT
    		  UPPER(PARSENAME(ClassDefs.Name,1)) AS "ClassName",
    		  fieldDef.value('Name[1]', 'nvarchar(max)') AS "FieldName",
    		  NULL AS "SubtypeName",
    		  fieldDef.value('DomainName[1]', 'nvarchar(max)') AS "DomainName"
    		FROM
    		  GDB_ITEMS AS ClassDefs
    		CROSS APPLY
    		  Definition.nodes('/*/GPFieldInfoExs/GPFieldInfoEx') AS FieldDefs(fieldDef)
      )
      
      SELECT ITEMS.[Name]
      FROM [dbo].[GDB_ITEMS] as ITEMS
      INNER JOIN GDB_ITEMTYPES as ITEMTYPES
    	on ITEMS.Type = ITEMTYPES.UUID
      WHERE (ITEMTYPES.Name = 'Coded Value Domain' OR ITEMTYPES.Name = 'Range Domain')
      AND ITEMS.[Name] NOT IN (SELECT DomainName FROM SUBDomainsAndFields WHERE DomainName is not null and DomainName <>'')
    CFDune
    by
    New Contributor

    For people who did find this script and want an updated one for ArcGIS Pro and use it in a toolbox. I've made a few changes to @BlakeTerhune script:

    import arcpy
    import os
    
    # Set workspace
    myGDB  = arcpy.GetParameterAsText(0)
    
    # Get domains that are assigned to a field
    domains_used = []
    for dirpath, dirnames, filenames in arcpy.da.Walk(myGDB, datatype=["FeatureClass", "Table"]):
        for filename in filenames:
            arcpy.AddMessage("Checking {}".format(os.path.join(dirpath, filename)))
            try:
                ## Check for normal field domains
                for field in arcpy.ListFields(os.path.join(dirpath, filename)):
                    if field.domain:
                        domains_used.append(field.domain)
                ## Check for domains used in a subtype field
                subtypes = arcpy.da.ListSubtypes(os.path.join(dirpath, filename))
                for stcode, stdict in subtypes.items():
                    if stdict["SubtypeField"] != u'':
                        for field, fieldvals in stdict["FieldValues"].items():
                            if not fieldvals[1] is None:
                                domains_used.append(fieldvals[1].name)
            except Exception as err:
                arcpy.AddMessage("Error:", err)
    
    # Get domains that exist in the geodatabase
    domains_existing = [dom.name for dom in arcpy.da.ListDomains(myGDB)]
    
    # Find existing domains that are not assigned to a field
    domains_unused = set(domains_existing) ^ set(domains_used)
    arcpy.AddMessage("{} unused domains in {}".format(len(domains_unused), myGDB))
    for domain in domains_unused:
        arcpy.DeleteDomain_management(myGDB, domain)
        arcpy.AddMessage("{} deleted".format(domain))

     

    Under tool properties you have to add a parameter to be used in the script:

    0 Kudos