Select to view content in your preferred language

ERROR 000358: Invalid expression Failed to execute (SelectLayerByAttribute)

8968
24
12-04-2015 11:45 AM
mattstutts
Emerging Contributor

My python script in ArcMap has an initial dialog box with two inputs: REG_CODE (values are in a list and include 'AKR', 'IMR', 'NER', etc) and Selection_type which offers 'NEW_SELECTION', 'REMOVE_FROM_SELECTION', etc.

My code runs just fine unless I pick the value 'NER'. Then I get this error:

Traceback (most recent call last): File "C:\Temp\SelectRegionalCREnterpriseData.py", line 99, in selectRelatedRecords(originTable, destinationTable, primaryKeyField, foreignKeyField) File "C:\Temp\SelectRegionalCREnterpriseData.py", line 96, in selectRelatedRecords arcpy.SelectLayerByAttribute_management(destinationTable, selectType, whereClause) File "c:\program files (x86)\arcgis\desktop10.2\arcpy\arcpy\management.py", line 6688, in SelectLayerByAttribute raise e ExecuteError: ERROR 000358: Invalid expression Failed to execute (SelectLayerByAttribute).

I can verify that my layers and tables have a valid field called REG_CODE, that 'NER' does exist as an attribute value, and that there are no associated NULL values in the CR_ID field.

The script does two things... 1) goes through each layer, and selects features where REG_CODE = (say, NER) 2) Finds all records in CR_Catalog table where REG_CODE = and then selects the related records in the CR_Link table.

import arcpy, os, string
import arcpy.mapping as MAP




#Needed CR layers as well as Catalog and Link tables should be loaded into current mxd
mxd = MAP.MapDocument("CURRENT")
df = MAP.ListDataFrames(mxd)[0]



#set Reg_Code value for regional data into a sql expression
fld = arcpy.AddFieldDelimiters(arcpy.env.workspace, "REG_CODE")
sqlExp = fld + " = " + " '{0}' ".format(arcpy.GetParameterAsText(0))
arcpy.AddMessage(sqlExp)
#set selection type
selectType = arcpy.GetParameterAsText(1)





#Make lists of all feature layers and another list of all tables in dataframe
layers = MAP.ListLayers(mxd, "", df)
tables = MAP.ListTableViews(mxd, "", df)



#Set destinationTable (CR_Link) to empty string. This gets populated only if Link table is loaded into mxd.
# else, the select layer by attribute tool doesn't run
destinationTable = ""
originTable = ""



#used in generating list of related CR_IDs for match Catalog to Link table. Related by CR_ID field.
primaryKeyField = "CR_ID"
foreignKeyField = "CR_ID"



#These will be used to get records in Link that are related to Catalog where #Reg_Code = <input>

for table in tables:
  descTable = arcpy.Describe(table)
  tableNameList = (descTable.name).split(".")
  tableName = tableNameList[-1]
   if tableName == "CR_Catalog":
  originTable = table
   elif tableName == "CR_Link":
  destinationTable = table
   else:
   pass





#Main code to select all records in Catalog with matching Reg_code and then getting related records in Link table

if not str(destinationTable) == "" and not str(originTable) == "":
   def buildWhereClauseFromList(originTable, primaryKeyField, valueList):
   # Add DBMS-specific field delimiters
  fieldDelimited = arcpy.AddFieldDelimiters(arcpy.Describe(originTable).path, primaryKeyField)

   # Determine field type
  fieldType = arcpy.ListFields(originTable, primaryKeyField)[0].type

   # Add single-quotes for string field values
   if str(fieldType) == 'String':
  valueList = ["'%s'" % value for value in valueList]

   # Format WHERE clause in the form of an IN statement
  whereClause = "%s IN(%s)" % (fieldDelimited, ', '.join(map(str, valueList)))
   return whereClause



 

 def selectRelatedRecords(originTable, destinationTable, primaryKeyField, foreignKeyField):
   ## Defines the record selection from the record selection of the OriginTable
   ## and applys it to the DestinationTable using a SQL WHERE clause built
   ## in the previous defintion"""

   # Set the SearchCursor to look through the selection of the OriginTable
  sourceIDs = set([row[0] for row in arcpy.da.SearchCursor(originTable, primaryKeyField, sqlExp)])



  

# Establishes the where clause used to select records from DestinationTable
  whereClause = buildWhereClauseFromList(destinationTable, foreignKeyField, sourceIDs)

   # Process: Select Layer By Attribute
  arcpy.SelectLayerByAttribute_management(destinationTable, selectType, whereClause)

   # Process: Select related records between OriginTable and DestinationTable
  selectRelatedRecords(originTable, destinationTable, primaryKeyField, foreignKeyField)

   del tables, tableName, tableNameList, primaryKeyField, foreignKeyField
   del originTable, destinationTable



#If Link isn't in mxd, send a message
else:
  arcpy.AddMessage("CR_Link and CR_Catalog tables must be added to dataframe in order to create selection in CR_Link")


for lyr in layers:
  fieldList = arcpy.ListFields(lyr.dataSource, "REG_CODE")
   if len(fieldList) == 1:
  arcpy.SelectLayerByAttribute_management(lyr, selectType, sqlExp)
   else:
   pass


del lyr, layers, 
del sqlExp, fld, mxd, df, fieldList 
0 Kudos
24 Replies
BruceHarold
Esri Regular Contributor

Toss that iThingy - get a Lumia like us real workers 😉

0 Kudos
mattstutts
Emerging Contributor

Although I was able to modify that script to fit my needs and get it to run.... I still get errors when the 'keyview' table has records selected where REG_CODE = 'NER'.    I don't get it.  There aren't null values in there.  This is insane.

0 Kudos
BruceHarold
Esri Regular Contributor

Hi, if you can share your data I will take a look.

0 Kudos
mattstutts
Emerging Contributor

That might take a while.  This is a large sde db with many feature classes and some sensitive data I'd have to remove.  I'll get around to this if necessary next week

0 Kudos
BruceHarold
Esri Regular Contributor

I spotted something suspicious.

Your code:

whereClause = "%s IN(%s)" % (fieldDelimited, ', '.join(map(str, valueList)))

INNER is of course a SQL reserved word, there isn't a space in IN('NER') and there may be a bug in the workspace SQL parser, please make sure you put a space between IN and the () part of the statement.  The () part must also have the strings quoted.  I use a construct like this:

values = ('NER','ABC','DEF')

whereClause = '{} IN {}'.format(arcpy.addFieldDelimiters(somefieldname),repr(values))

mattstutts
Emerging Contributor

That'd make sense if it weren't for the fact that I've since been working w/the other script you pointed me to that doesn't use that whereClause.  And again, it bombs out on NER.  here's a portion of what I've been working on:

# Process: Select Layer By Attribute to pre-select records in catalogTable where REG_CODE = <input>

    arcpy.SelectLayerByAttribute_management(catalogTable, selOption, sqlExp)

    #  Environment

    arcpy.env.qualifiedFieldNames = False

    # Get the set of selected OIDs in the input

    desc = arcpy.Describe(linkTable)

    fidSet = desc.FIDSet

    if fidSet:

        fidList = fidSet.replace(' ','').split(';')

        oidSet = set([int(oid) for oid in fidList])

    else:

        oidSet = set()

    # Get a set of key values

    arcpy.AddMessage('Finding unique key field values...\n')

    keyValues = set([row[0] for row in arcpy.da.SearchCursor(catalogTable,"CR_ID")])

    # Extract all candidate target OIDs and their key field values

    # We operate on this set for later selection on ObjectID

    arcpy.AddMessage('Finding input table ObjectID and key field mapping...\n')

    sourcePath = os.path.join(desc.path,desc.name)

    tmpView = "tmpView"

    arcpy.MakeTableView_management(sourcePath,tmpView)

    oidKVDict = {row[0]:row[1] for row in arcpy.da.SearchCursor(tmpView,

                                                                ['OID@',"CR_ID"])}

    #oidKVList = [(k, v) for (k, v) in oidKVDict.items()]

    oidKVList = [(k, v) for (k, v) in list(oidKVDict.items())]

    allSet = set([t[0] for t in oidKVList])

    # Find OID values to select on

    arcpy.AddMessage('Finding selection set...\n')

    if selOption == 'NEW_SELECTION': # Adopt value set

        oidList = sorted([t[0] for t in oidKVList if t[1] in keyValues])

    elif selOption == 'ADD_TO_SELECTION': # Add value set

        addSet = set([t[0] for t in oidKVList if t[1] in keyValues])

        oidSet |= addSet

        oidList = sorted(list(oidSet))

    elif selOption == 'REMOVE_FROM_SELECTION': # Common values removed

        remSet = set([t[0] for t in oidKVList if t[1] in keyValues and t[0] in oidSet])

        oidSet -= remSet

        oidList = sorted(list(oidSet))

    elif selOption == 'SUBSET_SELECTION': # Common values retained

        andSet = set([t[0] for t in oidKVList if t[1] in keyValues])

        oidSet &= andSet

        oidList = sorted(list(oidSet))

    else:

        arcpy.AddError('Unknown selection option\n')

        sys.exit(0)

    # Make the selection

    arcpy.AddMessage('Selecting...\n')

    compOIDList = sorted(list(allSet - set(oidList)))

    if len(compOIDList) == 0: # select all

        whereClause = '{} is not null'.format(desc.OIDFieldName)

    elif len(oidList) == 0: # select none

        whereClause = '{} < 0'.format(desc.OIDFieldName)

    elif len(oidList) <= len(compOIDList):

        inStatement = repr(tuple(oidList)).replace(',)',')')

        whereClause = '{} in {}'.format(desc.OIDFieldName,inStatement)

    else:

        inStatement = repr(tuple(compOIDList)).replace(',)',')')

        whereClause = '{} not in {}'.format(desc.OIDFieldName,inStatement)

    arcpy.SelectLayerByAttribute_management(linkTable,'NEW_SELECTION',whereClause)

    #arcpy.SetParameter(5,linkTable)

    arcpy.Delete_management(tmpView)

0 Kudos
mattstutts
Emerging Contributor

I should point out.. .It bombs on this specifically... only when I pick 'NER'

arcpy.SelectLayerByAttribute_management(linkTable,'NEW_SELECTION',whereClause)

0 Kudos
BruceHarold
Esri Regular Contributor

My money is still on some reserved word issue, lets do this by brute force when you can share your data.  Thanks.

0 Kudos
mattstutts
Emerging Contributor

I'll try to get some data but I don't think that's right.  Again, with the new version I'm working on, I've already pre-selected all the records in the catalog table where REG_CODE = 'NER'.  The code you pointed me to, doesn't rely on that at all.  It uses OID, from what I understand.  So, 'NER' is never being passed, looked at, or touched in any way.  Instead, I'm wondering if there is some kind of odd typo going on with one of the CR_ID values in either table.  I'm not sure.

0 Kudos
mattstutts
Emerging Contributor

One last thing...  Quite interesting...

I was in the process of exporting some data to shapefile.  I used a subset of one layer and exported all of the two tables mentioned (catalog and link).  I ran both versions of my code... the one that uses SQL and the code you pointed me to that I reconfigured for my needs.

BOTH WORKED.  So, what's different?  Each code is getting hung up on the section where they try to get related records from the Link table based on what's selected in the Catalog table (REG_CODE = 'NER').

The tables are the same in my exported versions....except they are stand-alone .dbfs.  My original tests were on live .sde tables.  I have no idea how to resolve this but maybe something is going on w/some of the 'NER' related records in my sde database?

0 Kudos