Sélection des fonctionnalités par attribut si dans la liste Python?


14

J'essaie de terminer une sélection par attribut en Python mais en me basant sur la question de savoir si un attribut est présent dans une liste.

Une telle requête dans sa forme la plus simple devrait ressembler à ceci:

qry = " \"OBJECTID\" in oid_list"
arcpy.SelectLayersByAttribute_management(inft, "NEW_SELECTION", qry)

mais cette approche renvoie une erreur d'expression non valide.

Dans le passé, j'ai dû utiliser une syntaxe plus compliquée pour ce type de requête, comme:

sqlQuery2 = "nid in (" + ','.join(["'"+x+"'" for x in delta_list]) +")"

mais une adaptation de cet extrait ne semble pas non plus fonctionner pour moi, c'est-à-dire:

 "OBJECTID_1 in (" + ','.join(["'"+str(x)+"'" for x in oid_list]) +")"

Qu'est-ce que j'oublie ici?

Réponses:


16

Votre requête d'origine aurait pu être modifiée pour une liste d'entiers:

'"OBJECTID_1" IN ' + str(tuple(oid_list))

donc si oid_list = [7, 9, 4, 8], alors le résultat est:

"OBJECTID_1" IN (7, 9, 4, 8)

Sachez que cette "astuce" fonctionne si elle oid_listcontient toujours deux éléments ou plus, car d'autres tuples valides, tels que ()ou (7,), entraîneront une erreur de syntaxe SQL.

Une expression plus générique qui gérerait également zéro ou un oid_listélément serait:

'"OBJECTID_1" IN ({0})'.format(', '.join(map(str, oid_list)) or 'NULL')

Je ne savais pas que l'interface de sélection ArcGIS était prise en charge «IN». C'est probablement plus efficace que ma solution.
AHigh

1
Méfiez-vous, il y a une limite supérieure qui est prise en charge par la requête IN. Je pense que c'est 2000 enregistrements
Tristan Forward

9

Voici une version légèrement modifiée de la fonction dans cette réponse , pour accepter une liste Python au lieu d'une chaîne délimitée par des points-virgules:

def buildWhereClauseFromList(table, field, valueList):
    """Takes a list of values and constructs a SQL WHERE
    clause to select those values within a given field and table."""

    # Add DBMS-specific field delimiters
    fieldDelimited = arcpy.AddFieldDelimiters(arcpy.Describe(table).path, field)

    # Determine field type
    fieldType = arcpy.ListFields(table, field)[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

6

Je pense que l'approche la plus simple consiste à parcourir les valeurs de votre liste individuellement et à les ajouter à la sélection (vous pouvez donc modifier votre requête avec chaque valeur de la liste). Quelque chose comme ça:

oidList = [1,2,3,4]
arcpy.management.MakeFeatureLayer(thisFC,thisLyr)
for values in oidList:
    query = "\"OBJECTID\"="+str(values)
    arcpy.management.SelectLayerByAttribute(thisLyr,"ADD_TO_SELECTION",query)

Vous pouvez utiliser ADD_TO_SELECTION même si aucune fonction n'est sélectionnée, il créera une nouvelle sélection à la première itération.

Éditer:

Si vous pensez que le coût de la réalisation de SelectLayerByAttribute individuel sera trop élevé, vous pouvez utiliser une approche comme celle-ci où vous créez une clause de sélection assez importante en fonction de la longueur de votre liste:

oidList = [1,2,3,4]
arcpy.management.MakeFeatureLayer(thisFC,thisLyr)
query=""
q=""
oidList.sort()
for x in oidList:
    query="\"OBJECTID\"="+str(x)+" OR "+q
    q=query
q=q[1:-4]
arcpy.management.SelectLayerByAttribute(thisLyr,"NEW_SELECTION",q)

Idée intéressante pour parcourir les valeurs et effectuer une sélection par attribut pour chaque itération. Je vais tester cela, mais je suis assez certain que cela devrait fonctionner. Merci.
jsnider

cela semble fonctionner, mais il faudra certainement du temps pour traiter chaque sélection individuelle pour des listes plus longues.
jsnider

2
Mise à jour de la réponse avec une approche différente.
AHigh

Bonne idée avec la réponse mise à jour. J'ai choisi d'utiliser cette approche car elle est beaucoup plus rapide pour traiter de plus grandes listes. Légèrement modifié: q = "" pour x dans oid_set: query = '"OBJECTID_1" =' + str (x) + 'OR' q = requête q = q [1: -4], puis sélectionnez par attribution. Semble fonctionner!
jsnider

Je mettrai à jour ma réponse avec votre approche choisie afin qu'elle soit analysée et plus facile à lire. Heureux que cela ait fonctionné.
AHigh
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.