Selezione delle caratteristiche per attributo se nell'elenco Python?


14

Sto cercando di completare una selezione per attributo in Python ma in base alla domanda se un attributo è presente in un elenco.

Una query del genere nella sua forma più semplice dovrebbe essere qualcosa del genere:

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

ma tale approccio restituisce un errore di espressione non valida.

In passato, ho dovuto usare una sintassi più complicata per questo tipo di query, come ad esempio:

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

ma un adattamento di questo frammento non sembra funzionare neanche per me, vale a dire:

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

Cosa mi sto perdendo qui?

Risposte:


16

La tua query originale avrebbe potuto essere modificata per un elenco di numeri interi:

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

quindi se oid_list = [7, 9, 4, 8], allora il risultato è:

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

Tenere presente che questo "trucco" funziona se oid_listha sempre due o più elementi, poiché altre tuple valide, come ()o (7,), risulteranno con un errore di sintassi SQL.

Un'espressione più generica che gestisca anche zero o un oid_listelemento sarebbe:

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

Non mi ero reso conto che l'interfaccia di selezione ArcGIS supportasse 'IN'. Questo è probabilmente più efficiente della mia soluzione.
— AHigh

1
Diffidate, c'è un limite superiore supportato dalla query IN, penso che sia 2000 record
— Tristan Forward

9

Ecco una versione leggermente modificata della funzione in questa risposta , per accettare un elenco Python invece di una stringa delimitata da punto e virgola:

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

Penso che l'approccio più diretto a questo sia quello di scorrere singolarmente i valori nella tua lista e aggiungerli alla selezione (così puoi cambiare la tua query con ogni valore nella lista). Qualcosa come questo:

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)

Puoi utilizzare ADD_TO_SELECTION anche se non ci sono funzionalità selezionate, creerà una nuova selezione alla prima iterazione.

Modificare:

Se ritieni che il costo per l'esecuzione di SelectLayerByAttribute individuale sia troppo elevato, potresti utilizzare un approccio come questo in cui crei una clausola di selezione piuttosto ampia a seconda della lunghezza dell'elenco:

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)

Interessante idea di scorrere i valori ed eseguire una selezione per attributo per ogni iterazione. Lo proverò, ma sono abbastanza sicuro che dovrebbe funzionare. Grazie.
— jsnider,

questo sembra funzionare, ma avrà sicuramente del tempo per elaborare ogni singola selezione per elenchi più lunghi.
— jsnider,

2
Aggiornato la risposta con un approccio diverso.
— AHigh

Buona idea con la risposta aggiornata. Ho scelto di utilizzare questo approccio in quanto molto più veloce per l'elaborazione di elenchi più grandi. Leggermente modificato: q = "" per x in oid_set: query = '"OBJECTID_1" =' + str (x) + 'OR' q = query q = q [1: -4] e quindi selezionare per attributo. Sembra funzionare!
— jsnider,

Aggiornerò la mia risposta con l'approccio scelto in modo che sia analizzato e più facile da leggere. Sono contento che abbia funzionato.
— AHigh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.