Програматично визначити приєднане поле в ArcMap?


9

Чи можливо програмно визначити поле приєднання , яке використовується для таблиці приєднання двох наборів даних разом у ArcMap? Наразі я використовую ArcGIS 10.0, SP5 і віддаю перевагу ArcPy-рішенню , однак я б не проти інших рішень, якщо рішення ArcPy недоступне.

Один із методів, який я спробував, перебирав усі поля і шукав відповідне "baseName", але це лише "освічена здогадка", де ви сподіваєтесь, що імена полів в обох базах даних однакові.

Для графічного зображення того, що я хочу, я в основному хочу визначити "Вхідне поле приєднання" та "Вихідне поле приєднання", як це видно в діалоговому вікні "Додати приєднання", але, звичайно, після факту.

Як ідентифікувати "Вхідне поле приєднання" та "Вихідне поле приєднання"?

Це питання про теги, чи можна «Приєднатись» виявити програмно? , але в цьому випадку я хочу розширити функціональність для виявлення FIELD (ив), які використовуються для об'єднання двох (або більше) наборів даних разом.


З якою версією 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

@lewis, вам не потрібно використовувати заводський об’єкт, щоб отримати посилання на існуючий RelQueryTable - дивіться мою відповідь.
blah238

Відповіді:


8

Ось підхід 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 (використовуючи комтити та цей допоміжний модуль ) буде проходити всі з'єднання, від останніх до найдавніших, та друкує назви таблиць призначення та вихідної таблиці, первинний ключ походження та зовнішній ключ для кожного з'єднання:

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?


Це виглядає дуже перспективно. У мене встановлений пакунок комтитів та доданий код функції помічника, але я отримую помилку "global name 'esriGeoDatabase' is not defined". Де / як це слід визначити в коді, що передує рядку while CType(table, esriGeoDatabase.IRelQueryTable)?
RyanKDalton

Я не включав його, але в якийсь момент вам доведеться імпортувати обгортки комтитів навколо конкретних бібліотек об’єктів ESRI, які вам потрібні. Використовувати мій модуль-помічник, це так само просто esriGeoDatabase = GetESRIModule("esriGeoDatabase").
blah238

Зрозумів дякую. Чи буде це працювати і для шарів в ArcMap? Я передаю кожен шар з layerList = arcpy.mapping.ListLayers(mxd)в listJoins(table)коді, але він пропускає поза в whileзаяві.
RyanKDalton

Я не думаю, що ви можете розміщувати між об'єктами arcpy та об'єктами comtypes, тому вам потрібно отримати посилання ILayer через ArcObjects. Я оновив код, щоб включити більш повний приклад. Це має бути використано як у процесі, так і поза ним, коментуючи / коментуючи відповідні рядки.
blah238

Наблизившись, дякую за терпіння терпіння ... тепер, як ви надіслали фактичний файл документа на карті (* .mxd), який ви хочете переглянути? app.Documentповертається з'NoneType' object has no attribute 'Document'
RyanKDalton

1

Покладіть всі дані полів у рядки (після їх замовлення) порівняйте їх з функцією нечіткої порівняння та виберіть тих, хто дав найкращу відповідність чи відповідність з певною точністю.

Це рішення полягає в тому випадку, коли деякі дані не підходять. Якщо ви думаєте, що обидва стовпці завжди підходять, просто замовляйте та порівнюйте для ідеального відповідності звичайній функції порівняння.


0

Спробуйте це:

  • Використовуйте інструмент трансформації XSLT з набору інструментів метаданих, щоб виписати файл метаданих 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-аналізатор для читання у файлі метаданих та пошуку поля приєднання з історії геопроцедури інструменту Join Field

  • Вибірка з інструменту трансформації XSLT

Вихід з інструменту трансформації XSLT


1
Це дійсно розумна ідея, на яку я думав, що справді обіцяє, але з мого тестування, здається, що це спрацює лише в тому випадку, якщо файл буде з'єднаний за допомогою інструменту GP під назвою "JoinField", оскільки це написано як частина історії процесів GP для цього шару. Якщо користувач створив з'єднання через користувальницький інтерфейс, у вихідному файлі рядок процесу JoinField не існує. Чудова ідея, хоча!
RyanKDalton

1
Я б ніколи не покладався на цю історію лікаря. Ми намагаємось видалити його якнайшвидше, оскільки для повторюваних процесів він швидко збирається у величезний обсяг даних, що робить клас функцій майже непридатним.
blah238

-1

Імена приєднаних таблиць знаходяться в об’єкті IFeatureLayer - IFeatureLayerDefinition як рядок .. який, на мою думку, ймовірно містить SQL приєднання, а отже, імена полів.

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

Або ти маєш на увазі, якщо ти не можеш отримати доступ до цього об’єкта?


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)

ей, хто би стукав мою відповідь: чи можете ви сказати мені, що не так у моїй відповіді? Дякую.
1313

1
Схоже, це не відповідає на запитання. Те саме з нечіткою відповіді відповіді. Поля, однакові (або навіть нечітко схожі), не мають ніякого відношення до того, чи справді вони використовувались у з'єднанні.
blah238
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.