Select to view content in your preferred language

Delete Unused Domains

20847
30
06-08-2015 11:50 AM
BlakeTerhune
MVP Alum

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 Alum

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 Alum

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

AndresCastillo
MVP Alum

Absolutely, me too!

Thank you for your awesome script!

JeremyLinley
Occasional Contributor

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 Alum

    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 Alum

    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 Notable 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
    Frequent Contributor

    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
    Occasional Contributor

    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: