Selecionando recursos por atributo se estiver na lista Python?

14

Eu estou tentando concluir uma seleção por atributo em Python, mas com base na consulta de se um atributo está presente em uma lista.

Essa consulta, na sua forma mais simples, deve ser algo como isto:

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

mas essa abordagem retorna um erro de expressão inválido.

No passado, eu tive que usar sintaxe mais complicada para esse tipo de consulta, como:

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

mas uma adaptação desse trecho também não parece funcionar para mim, ou seja:

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

O que estou perdendo aqui?

jsnider
fonte

Respostas:

16

Sua consulta original pode ter sido modificada para uma lista de números inteiros:

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

então oid_list = [7, 9, 4, 8], se o resultado é:

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

Esteja ciente de que esse "truque" funciona se oid_listsempre tiver dois ou mais itens, pois outras tuplas válidas, como ()ou (7,), resultarão em um erro de sintaxe SQL.

Uma expressão mais genérica que também manipularia zero ou um oid_listitem seria:

'"OBJECTID_1" IN ({0})'.format(', '.join(map(str, oid_list)) or 'NULL')
Mike T
fonte
Não percebi que a interface de seleção do ArcGIS suporta 'IN'. Provavelmente isso é mais eficiente que minha solução.
ahigh
1
Basta ser cauteloso existe um limite superior que é suportado pela IN consulta Eu acho que é 2000 registros
Tristan Atacante
9

Aqui está uma versão ligeiramente modificada da função nesta resposta , para aceitar uma lista Python em vez de uma string delimitada por ponto e vírgula:

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
blah238
fonte
6

Eu acho que a abordagem mais direta é iterar os valores da sua lista de maneira singular e adicioná-los à seleção (para que você possa alterar sua consulta com cada valor da lista). Algo assim:

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)

Você pode usar o ADD_TO_SELECTION mesmo que não haja recursos selecionados, ele criará uma nova seleção na primeira iteração.

Editar:

Se você acha que o custo de executar SelectLayerByAttribute individual é muito alto, você pode usar uma abordagem como essa, onde cria uma cláusula de seleção bastante grande, dependendo do tamanho da sua lista:

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)
Um alto
fonte
Ideia interessante para iterar pelos valores e executar uma seleção por atributo para cada iteração. Vou testar isso, mas tenho certeza de que isso deve funcionar. Obrigado.
jsnider
isso parece estar funcionando, mas certamente levará algum tempo para processar cada seleção individual para listas mais longas.
jsnider
2
Atualizou a resposta com uma abordagem diferente.
ahigh
Boa ideia com a resposta atualizada. Eu escolhi usar essa abordagem, pois é muito mais rápida para processar listas maiores. Ligeiramente modificado: q = "" para x em oid_set: query = '"OBJECTID_1" =' + str (x) + 'OR' q = query q = q [1: -4] e selecione bytribute. Parece funcionar!
jsnider
Atualizarei minha resposta com a abordagem escolhida para que seja analisada e mais fácil de ler. Ainda bem que funcionou.
ahigh