Программно идентифицировать объединенное поле в ArcMap?

9

Можно ли программно идентифицировать поле соединения , которое используется для объединения двух наборов данных в ArcMap? В настоящее время я использую ArcGIS 10.0, SP5 и предпочитаю решение ArcPy , однако я не буду против других решений, если решение ArcPy недоступно.

Один из методов, который я пробовал, заключался в том, чтобы пройтись по всем полям и найти соответствующее «baseName», но это всего лишь «обоснованное предположение», когда вы надеетесь, что имена полей в обеих базах данных совпадают.

Для графического представления того, что мне нужно, я в основном хочу определить «Поле входного соединения» и «Поле выходного соединения», как это видно в диалоговом окне «Добавить объединение», но, конечно же, постфактум.

Как определить «поле входного соединения» и «поле выходного соединения»?

Это вопрос к тегу « Можно ли программно обнаружить« Присоединение »? , но в этом случае я хочу расширить функциональность, чтобы идентифицировать поля, которые используются для объединения двух (или более) наборов данных вместе.

RyanKDalton
источник
С какой версией ArcGIS вы работаете? И я полагаю, основываясь на тегах, которые вы ищете специально для этого, используя arcpy, а не ArcObjects?
blah238
В настоящее время я использую ArcGIS 10.0, SP5. И да, я ищу / надеюсь на решение ArcPy, однако я не был бы против решения ArcObjects, если бы это была единственная альтернатива.
RyanKDalton
1
Вот, возможно, важная документация: edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/…. Это включает pRelClass. Это RelationshipClass, используемый для определения таблиц соединения и полей соединения, а также количества элементов. Метод Open либо создает новый RelQueryTable, либо возвращает ссылку на существующий RelQueryTable, если этот класс уже создан. Вы можете вызвать этот метод и найти ссылку с участием thepRelClass
Левис
@ lewis, вам не нужно использовать объект фабрики, чтобы получить ссылку на существующую RelQueryTable - смотрите мой ответ.
blah238

Ответы:

7

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

  1. Получить ссылку на ILayerодно или несколько объединений
  2. Примените ILayerкIDisplayTable
  3. Привести IDisplayTable.DisplayTableсобственность кIRelQueryTable
  4. В то время как текущая таблица является IRelQueryTable:
    1. Проверьте RelQueryTable«S DestinationTableи SourceTableсвойства
    2. Осмотрите OriginPrimaryKeyи OriginForeignKeyсвойства IRelQueryTable.RelationshipClassсобственности.
    3. Установите текущую таблицу в текущей RelQueryTable«s SourceTableнедвижимости

Этот сценарий Python (с использованием comtypes и этого вспомогательного модуля ) будет проходить через все объединения, от самого раннего до самого раннего, и печатать имена таблиц назначения и исходной таблицы, первичный ключ источника и внешний ключ источника для каждого соединения:

from ESRICOMHelpers import * # helper module from https://gis.stackexchange.com/a/5082/753
esriArcMapUI = GetESRIModule("esriArcMapUI")
esriCarto = GetESRIModule("esriCarto")
esriGeoDatabase = GetESRIModule("esriGeoDatabase")

def listJoins(table):
    while CType(table, esriGeoDatabase.IRelQueryTable):
        relQueryTable = CType(table, esriGeoDatabase.IRelQueryTable)
        destTable = relQueryTable.DestinationTable
        sourceTable = relQueryTable.SourceTable
        destDataset = CType(destTable, esriGeoDatabase.IDataset)
        sourceDataset = CType(sourceTable, esriGeoDatabase.IDataset)
        relClass = relQueryTable.RelationshipClass
        print destDataset.Name, sourceDataset.Name, relClass.OriginPrimaryKey, relClass.OriginForeignKey
        table = sourceTable

if __name__ == "__main__":
    #app = GetCurrentApp() # Use if run in-process
    app = GetApp("ArcMap") # Use if run in a standalone script
    mxd = CType(app.Document, esriArcMapUI.IMxDocument)

    # Gets the first layer in the active data frame
    map = mxd.FocusMap
    lyr = map.Layer[0]

    # Need to get the "display table" to access the joins
    displayTable = CType(lyr, esriCarto.IDisplayTable).DisplayTable

    # List the layer's joined tables
    listJoins(displayTable)

Пример вывода для исходного слоя с тремя объединениями:

join_table_3 master_fc_join_table_1_join_table_2 JOIN_ID_3 master_fc.MASTER_ID
join_table_2 master_fc_join_table_1 JOIN_ID_2 master_fc.MASTER_ID
join_table_1 master_fc JOIN_ID_1 MASTER_ID

Для получения дополнительной информации см. Как получить доступ к ArcObjects из Python?

blah238
источник
Это выглядит очень многообещающе. У меня установлен пакет comtypes и добавлен код вспомогательной функции, но я получаю сообщение об ошибке "global name 'esriGeoDatabase' is not defined". Где / Как это должно быть определено в коде, предшествующем строке while CType(table, esriGeoDatabase.IRelQueryTable)?
RyanKDalton
Я не включил его, но в какой-то момент вы должны импортировать обертки comtypes вокруг определенных библиотек объектов ESRI, которые вам нужны. Используя мой вспомогательный модуль это так же просто, как esriGeoDatabase = GetESRIModule("esriGeoDatabase").
blah238
Понял, спасибо. Будет ли это работать для слоев в ArcMap? Я передаю каждый слой из layerList = arcpy.mapping.ListLayers(mxd)в listJoins(table)код, но он пропускает при whileутверждении.
RyanKDalton
Я не думаю, что вы можете приводить между объектами arcpy и объектами Comtipes, поэтому вам нужно получить ссылку на ILayer через ArcObjects. Я обновил код, чтобы включить более полный пример. Это должно быть в состоянии использоваться как в процессе, так и вне процесса, комментируя / раскомментируя соответствующие строки.
blah238
Приближаясь, спасибо за проявленное терпение ... теперь, как вы отправили фактический файл документа карты (* .mxd), на который хотите посмотреть? app.Documentвозвращается с'NoneType' object has no attribute 'Document'
RyanKDalton
1

Поместите все данные полей в строки, (после их упорядочивания) сравните их с функцией нечеткого сравнения и выберите тех, кто дал наилучшее совпадение или совпадение с определенной точностью.

Это решение, когда некоторые данные не подходят. Если вы считаете, что оба столбца всегда подходят, просто упорядочите и сравните для идеального соответствия с обычной функцией сравнения.

Ниже радара
источник
0

Попробуй это:

  • Используйте инструмент XSLT Transformation из набора инструментов метаданных, чтобы записать файл метаданных xml / html для рассматриваемого набора данных.

    arcpy.XSLTransform_conversion(r'X:\temp\Scratch.gdb\fc_FeatureToPoint',"C:\Program Files\ArcGIS\Desktop10.1\Metadata\Stylesheets\ArcGIS.xsl", r'X:\temp\Metadata.html')
  • Используйте анализатор HTML для чтения в файле метаданных и поиска поля соединения из истории геообработки инструмента Поле соединения

  • Пример вывода из инструмента XSLT Transformation

Выходные данные из инструмента XSLT Transformation

Nxaunxau
источник
1
Это действительно умная идея, которая, как мне показалось, имела многообещающее значение, но из моего тестирования выяснилось, что это сработает только в том случае, если файл будет объединен с помощью инструмента GP под названием JoinField, так как он написан как часть истории процесса GP для этого слоя. Если пользователь создал соединение через пользовательский интерфейс, строка процесса JoinField не существует в выходном файле. Отличная идея, хотя!
RyanKDalton
1
В любом случае, я бы не стал полагаться на историю GP. Мы пытаемся удалить его как можно скорее, потому что для повторяющихся процессов он быстро монтируется в огромный объем данных, что делает класс объектов почти непригодным для использования.
blah238
-1

Имена соединенных таблиц находятся в объекте IFeatureLayer - IFeatureLayerDefinition в виде строки, которая, я думаю, вероятно, содержит объединяющий SQL и, следовательно, имена полей.

http://edndoc.esri.com/arcobjects/8.3/diagrams/Map%20Layer%20Object%20Model.pdf

Или вы имеете в виду, если вы не можете получить доступ к этому объекту?

AnserGIS
источник
IFeatureLayerDefinitionне содержит "SQL соединения", у него есть только DefinitionExpressionсвойство, отображающее запрос определения векторного слоя, если он установлен, - это предложение WHERE, которое ограничивает отображаемые строки.
blah238
Однако у него есть RelationshipClassсвойство, но я думаю, что это только самое последнее соединение. Вы должны использовать IRelQueryTableвместо этого, чтобы получить их все.
blah238
-2

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

import arcpy

fc = r"temp/RiversJoined.shp"

fldList1 = [f.name for f in arcpy.ListFields(fc)]
fldList2 =[g.name for g in arcpy.ListFields(fc)]

for f in fldList1:
    values1 = [f_row[0] for f_row in arcpy.da.SearchCursor(fc, (f))]
    for g in fldList2:
        values2 = [g_row[0] for g_row in arcpy.da.SearchCursor(fc,(g))]
        #compare field values
        #get names of matching fields
        if (fldList2.index(g) != fldList1.index(f) and values1 == values2):
            print "match: " + str(g) + " match: "+ str(f)
mwil
источник
Эй, кто бы ни стукнул мой ответ: можешь сказать, что не так с моим ответом? Спасибо.
mwil
1
Похоже, это не отвечает на вопрос, который задают. То же самое с нечетким сравнительным ответом. Поля, являющиеся идентичными (или даже нечетко подобными), не имеют никакого отношения к тому, были ли они фактически использованы в соединении.
blah238