3

I need to remove fields within file GDB and SDE databases that contain only empty or null values. I was hoping to do this for an entire database at a time rather than per feature class. The code below shows the best of what I have so far. It does not, however, accomplish what I had hoped. I am somewhat new to Python and am using ArcMap 10.3.1.

import arcpy  
from arcpy import env  
env.workspace = r"C:\New Folder\Default.gdb"

def DelFields(path):
    env.workspace = path
    # first need to point to FCs within DSs
    datasets = arcpy.ListDatasets(feature_type='All')
    datasets = [''] + datasets if datasets is not None else []

    for ds in datasets:
        for fc in arcpy.ListFeatureClasses(feature_dataset=ds):
            # list comp syntax:
            # [{code}var{code} for var in [list] if var{logic test}]. 
            fieldList = [f.name for f in arcpy.ListFields(fc) if f.type ==
                         "Short" or "Long" or "Float" or "Double" or "Text" or
                         "Date" or "Blob" or "Raster" or "Guid"] # "All" did not work                
            print fieldList # to see what I have so far

            if fieldList: # this is a bit of a long shot I think
                # The UpdateCursor line gives error:
                # TypeError: 'field_names' must be string or non empty sequence of strings
                with arcpy.da.UpdateCursor(fc, [fieldList]) as cursor:
                    for row in cursor: 
                        for i in range (len(fieldList)):
                            if row[i].rstrip() == "": # trying to find empties
                                arcpy.DeleteField_management(path, fieldList) 
                            elif row[i] == "<Null>": # trying to find Nulls
                                arcpy.DeleteField_management(path, fieldList)
                                cursor.updateRow(row)

DelFields(r"C:\New Folder\Default.gdb")
  • You probably need to put some more details in your post, like what exactly IS it doing that you don't expect. However, at first glance, I do believe == "<Null>" should be replaced with Is None. None is Python's null. – Richard Morgan Aug 3 '16 at 20:58
5

Try this; see the comments for explanation.

import os
import arcpy
from arcpy import env

def DelFields(path):
    env.workspace = path
    # Get a list of feature classes directly (i.e., not within feature datasets)
    #   the geodatabase
    fcs = arcpy.ListFeatureClasses()
    # Add the relative paths of feature classes that are within feature
    #   datasets
    fcs.extend([os.path.join(fd, fc) for fd in arcpy.ListDatasets() for fc in arcpy.ListFeatureClasses(feature_dataset=fd)])

    # Iterate over the feature classes
    for fc in fcs:
        # Test whether the field is required--rather than testing the field type
        fieldList = [f.name for f in arcpy.ListFields(fc) if not f.required]

        # Iterate over the fields
        for field in fieldList:
            # Set a test variable to False
            keep = False
            # Iterate over each feature; if it has a non-null value, then set
            #   the test variable to True and then break out of the cursor
            with arcpy.da.SearchCursor(fc, field) as cursor:
                for row in cursor:
                    v = row[0]
                    if v is not None or \
                      (isinstance(v, basestring) \
                      and (v.lower.strip() != ''\
                        or v != '<null>')):
                        keep = True
                        break

            # If the test variable was unchanged, delete the field
            if keep is False:
                arcpy.DeleteField_management(fc, field)

DelFields(r"C:\tlax490\data\temp\temp.gdb")

EDIT: I've changed the if statement within the cursor to test for your desired null-like strings.

To catch similar cases that you might otherwise miss, you can determine whether the value is a string, and if so, lowercase it and then remove empty spaces on the outsides. If the result is your bracketed null or an empty string, then it will be considered null.

  • I accepted your answer @Tom because it was very helpful. Thanks. I changed the field iteration to if row[0] is not None or "<Null>" or " ": Doing this resulted in many more fields being deleted. Many empty and Null fields remain, however. Many of those that remain are strings. Though some of the deleted fields were strings as well. I am not sure whats wrong with the code, but I will try to determine why these fields were not deleted. – reevesii Aug 4 '16 at 15:01
  • 1
    @reevesii, that's a common mistake. If you change that line, you should change it to something like if row[0] is not None or row[0] != '<Null>' or row[0] != ' '. Otherwise, you're just testing whether the string objects '<Null>' and ' ' are not equal to False, and that is True. See the update in the code of my answer. – Tom Aug 4 '16 at 15:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.