以编程方式识别ArcMap中的联接字段?


9

是否可以以编程方式标识用于在ArcMap中将两个数据集表联接在一起的联接字段?我目前正在使用ArcGIS 10.0,SP5,并且希望使用ArcPy解决方案,但是如果没有ArcPy解决方案,我不会反对其他解决方案。

我尝试过的一种方法是遍历所有字段并查找匹配的“ baseName”,但这只是一个“有根据的猜测”,您希望两个数据库中的字段名相同。

对于我所需要的内容的图形表示,我基本上想标识“输入连接字段”和“输出连接字段”,如“添加连接”对话框中所示,但实际上是事后的。

如何识别“输入联接字段”和“输出联接字段”?

这是一个标记问题,可以通过编程方式检测“加入”吗?,但是在这种情况下,我想扩展功能以识别用于将两个(或多个)数据集连接在一起的FIELD。


您正在使用哪个版本的ArcGIS?我假设根据您正在寻找的标记专门使用arcpy而不是ArcObjects进行标记?
blah238 2013年

我当前正在使用ArcGIS 10.0,SP5。是的,我正在寻找/希望有一个ArcPy解决方案,但是如果那是唯一的选择,我不会反对ArcObjects解决方案。
RyanKDalton 2013年

1
以下是一些可能的启示性文档:edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase / ...它涉及pRelClass这是用来定义联接表和联接字段以及基数的RelationshipClass。Open方法将创建一个新的RelQueryTable或返回对现有RelQueryTable的引用(如果已经创建了该类)。您可以调用此方法并找到涉及thepRelClass的引用
lewis

@lewis,您不需要使用工厂对象来获取对现有RelQueryTable的引用-请参阅我的答案。
blah238

Answers:


7

基于此示例,这是一个ArcObjects方法,用于枚举层上的所有联接并列出其目标和源表名称以及主键和外键:

  1. 获得对ILayer具有一个或多个联接的的引用
  2. 投放ILayerIDisplayTable
  3. IDisplayTable.DisplayTable属性投放到IRelQueryTable
  4. 当前表是IRelQueryTable
    1. 检查RelQueryTableDestinationTableSourceTable属性
    2. 检查OriginPrimaryKeyOriginForeignKey的性能IRelQueryTable.RelationshipClass特性。
    3. 将当前表设置为current RelQueryTableSourceTable属性

此Python脚本(使用comtypes和此helper模块)将从最新到最早遍历所有联接,并为每个联接打印目标和源表名称,原始主键和原始外键:

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

有关更多信息,请参见如何从Python访问ArcObjects?


这看起来很有希望。我已经安装了comtypes软件包,并添加了辅助函数代码,但出现了错误"global name 'esriGeoDatabase' is not defined"。该行前面的代码中的何处/应如何定义while CType(table, esriGeoDatabase.IRelQueryTable)
RyanKDalton

我没有包含它,但是在某些时候,您必须围绕所需的特定ESRI对象库导入comtype包装器。使用我的帮助器模块,就像一样简单esriGeoDatabase = GetESRIModule("esriGeoDatabase")
blah238 2013年

知道了谢谢。这也适用于ArcMap中的图层吗?我正在将每一层都传递layerList = arcpy.mapping.ListLayers(mxd)listJoins(table)代码中,但是跳过了该while语句。
RyanKDalton

我认为您不能在arcpy对象和comtypes对象之间进行转换,因此您需要通过ArcObjects获得ILayer引用。我已经更新了代码以包含一个更完整的示例。通过注释/取消注释相关行,应该可以在过程中和过程外使用此功能。
blah238

越来越近了,感谢您的逐步耐心等待...现在,您如何发送要查看的实际地图文档文件(* .mxd)? app.Document回来了'NoneType' object has no attribute 'Document'
RyanKDalton

1

将字段的所有数据放入字符串中(在对它们进行排序之后),将它们与Fuzzycompare函数进行比较,然后选择给出最佳匹配或匹配beyound的特定精度的那些。

此解决方案是在某些数据无法容纳时。如果您认为两列都将始终适合,则只需排序并比较即可使用普通的比较功能完美匹配。


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解析器读取元数据文件,并从“联接字段”工具的地理处理历史记录中搜索联接字段

  • XSLT转换工具的样本输出

XSLT转换工具的输出


1
我认为这是一个非常聪明的主意,但是从我的测试来看,这似乎只有在使用名为“ JoinField”的GP工具连接文件时才有效,因为这是GP进程历史的一部分对于那一层。如果用户通过UI创建了联接,则输出文件中不存在JoinField进程行。好主意!
RyanKDalton 2013年

1
无论如何,我不会依赖GP的历史。我们尝试尽快删除它,因为对于重复进行的过程,它会迅速装入大量数据中,从而使要素类几乎无法使用。
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)

嘿,有人敲了我的答案:您能告诉我我的答案有什么问题吗?谢谢。
mwil

1
这似乎没有回答所问的问题。与模糊比较答案相同。相同(或什至模糊相似)的字段与它们是否实际用于联接无关。
blah238
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.