Выбор объектов по атрибуту, если в списке Python?

14

Я пытаюсь выполнить выбор по атрибуту в Python, но на основе запроса о том, присутствует ли атрибут в списке.

Такой запрос в самом простом виде должен выглядеть примерно так:

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

но этот подход возвращает недопустимую ошибку выражения.

В прошлом мне приходилось использовать более сложный синтаксис для этого типа запроса, например:

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

но адаптация этого фрагмента мне тоже не подходит, т.е.

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

Что мне здесь не хватает?

jsnider
источник

Ответы:

16

Ваш исходный запрос мог быть изменен для списка целых чисел:

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

так что если oid_list = [7, 9, 4, 8], то результат:

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

Имейте в виду, что этот «трюк» работает, если oid_listвсегда содержит два или более элементов, поскольку другие допустимые кортежи, такие как ()или (7,), приведут к ошибке синтаксиса SQL.

Более общее выражение, которое также обрабатывает ноль или один oid_listэлемент, будет:

'"OBJECTID_1" IN ({0})'.format(', '.join(map(str, oid_list)) or 'NULL')
Майк Т
источник
Я не понял, что интерфейс выбора ArcGIS поддерживает IN. Это, вероятно, более эффективно, чем мое решение.
AHigh
1
Только будьте осторожны, есть верхний предел, который поддерживается запросом IN, я думаю, что это 2000 записей
Tristan Forward
9

Вот немного измененная версия функции в этом ответе , чтобы принять список Python вместо строки, разделенной точкой с запятой:

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
источник
6

Я думаю, что самый простой подход к этому состоит в том, чтобы перебирать значения в вашем списке по отдельности и добавлять их в выборку (так что вы можете изменить свой запрос с каждым значением в списке). Что-то вроде этого:

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)

Вы можете использовать ADD_TO_SELECTION, даже если нет выбранных объектов, это создаст новый выбор на первой итерации.

Редактировать:

Если вы считаете, что стоимость создания отдельного SelectLayerByAttribute будет слишком высокой, вы можете использовать такой подход, когда вы создаете довольно большое предложение выбора в зависимости от длины списка:

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)
Высота
источник
Интересная идея - перебирать значения и выполнять выборку по атрибуту для каждой итерации. Я проверю это, но я уверен, что это должно сработать. Благодарю.
jsnider
кажется, что это работает, но, безусловно, потребуется время для обработки каждого отдельного выбора для более длинных списков.
jsnider
2
Обновил ответ с другим подходом.
AHigh
Хорошая идея с обновленным ответом. Я решил использовать этот подход, так как он намного быстрее для обработки больших списков. Немного изменено: q = "" для x в oid_set: query = '"OBJECTID_1" =' + str (x) + 'OR' q = запрос q = q [1: -4] и затем выберите атрибут атрибута. Кажется, работает!
jsnider
Я обновлю свой ответ выбранным вами подходом, чтобы он был проанализирован и его было легче читать. Рад, что это сработало.
AHigh