0

I have a personal geodatabase with a polygon feature class with a one-to-many relationship to a table.

What I want to do is to export to a shapefile with all the infornation associated in every polygon.

I use ArcGis 10.2.1

3
  • 1
    Would you be able to edit your question to indicate whether you are trying to do this using ArcGIS for Desktop (and version) or QGIS or something else, please?
    – PolyGeo
    Commented Apr 29, 2015 at 11:58
  • Are you wanting duplicate features in the shp to represent the many features or wanting some sort of type/quantity field in the shp representing the many features?
    – artwork21
    Commented Apr 29, 2015 at 12:05
  • I want to duplicate the features. Commented Apr 29, 2015 at 12:08

1 Answer 1

0

I have used this script in the past. It is designed to work in ArcMap where you select records and it will select all related records and export to a new feature class, creating duplicate geometries for each related record.

import arcpy, os, sys
arcpy.env.ovewriteOutput = True
arcpy.env.qualifiedFieldNames = False

def SelectRelatedRecords(in_ft, in_field, rel_table, rel_field, sql='',export=False, out_fc=''):

    '''
    Selects all features from input layer based on selection from another table.  Acts like
      a "relationship class".  There must be a common field between the two tables.

    in_ft = input features
    in_field = field for the relate from input features
    rel_table = related table
    rel_field = related table field
    sql = where clause for the input features (optional)
    export = Boolean option to export related records.  Default is False.
    out_fc = Output feature class.  This parameter is only enabled
      if export is True.
    '''

    # Check to make sure field types match, otherwise raise error and exit tool
    in_ft_desc = arcpy.Describe(in_ft)
    ftype1 = [f.type for f in in_ft_desc.fields if f.name == in_field][0]
    ftype2 = [f.type for f in arcpy.Describe(rel_table).fields if f.name == rel_field][0]
    if ftype1 != ftype2:
        arcpy.AddError('\nField type for "{0}" in "{1}" does not match field type for "{2}"' \
                       ' in "{3}"!\n'.format(in_field,in_ft,rel_field,rel_table))
        arcpy.AddError('Field type is "{0}", must be "{1}".\n'.format(ftype1,ftype2))
        sys.exit()

    # map doc
    mxd = arcpy.mapping.MapDocument('CURRENT')
    df = arcpy.mapping.ListDataFrames(mxd)[0]

    # determine version for cursor type 
    ver = arcpy.GetInstallInfo()['Version']
    if ver != '10.0':
        dataAccess = True
    else:
        dataAccess = False

    # make feature layer if sql
    if sql not in ('', '#'):
        arcpy.SelectLayerByAttribute_management(in_ft, 'NEW_SELECTION', sql)
    sel_count = int(arcpy.GetCount_management(in_ft).getOutput(0))
    arcpy.AddMessage('\n{0} selected records from from "{1}"\n'.format(sel_count, in_ft))

    # grab unique id's
    if dataAccess:
        with arcpy.da.SearchCursor(in_ft, ['SHAPE@', in_field]) as rows:
            geom_dict = dict((r[1], r[0]) for r in rows)

    else:
        rows = arcpy.SearchCursor(in_ft)
        geom_dict = dict((r.getValue(in_field), r.shape) for r in rows)
        del rows

    # get keys
    if ftype1 == 'String':
            recs = tuple(filter(None, [k.encode('utf-8') for k in geom_dict.keys()]))
    else:
        recs = tuple(filter(None, geom_dict.keys()))

    # Select records in related table
    rel_path = os.path.dirname(arcpy.Describe(rel_table).catalogPath)
    where = ''' {0} in {1} '''.format(arcpy.AddFieldDelimiters(rel_path, rel_field), recs)
    arcpy.SelectLayerByAttribute_management(rel_table, 'NEW_SELECTION', where)
    rel_count = int(arcpy.GetCount_management(rel_table).getOutput(0))
    arcpy.AddMessage('Selected {0} related records from "{1}"\n'.format(rel_count, rel_table))


    # if export is true, create output features
    if export in [True,'true',1]:
        if out_fc:
            # See if there are many to one relationships
            if rel_count > sel_count:
                # get counts of keys
                if dataAccess:
                    with arcpy.da.SearchCursor(rel_table, [rel_field]) as rows:
                        recs2 = [r[0] for r in rows]
                else:
                    rows = arcpy.SearchCursor(rel_table)
                    recs2 = [r.getValue(rel_field) for r in rows]
                    del rows

                # get counts
                features = []
                for rec in recs:
                    for i in range(recs2.count(rec)):
                        features.append((geom_dict[rec], rec))

                # make new feature class
                tmp = r'in_memory\tmp_lyr_xyz123'
                sType = in_ft_desc.shapeType.upper()
                path, name = os.path.split(tmp)
                arcpy.CreateFeatureclass_management(path, name, sType, '', '', '',
                                                    in_ft_desc.spatialReference)
                f_length = [f.length for f in in_ft_desc.fields if f.name == in_field][0]
                tmp_field = 'TMP_JN_XYZ'
                arcpy.AddField_management(tmp, tmp_field, ftype1, field_length=f_length)

                # insert geometry
                if dataAccess:
                    with arcpy.da.InsertCursor(tmp, ['SHAPE@', tmp_field]) as irows:
                        for feats in features:
                            irows.insertRow(feats)
                else:
                    irows = arcpy.InsertCursor(tmp)
                    for feats in features:
                        irow = irows.newRow()
                        irow.shape = feats[0]
                        irow.setValue(tmp_field, feats[1])
                        irows.insertRow(irow)
                    del irow, irows

                # Make feature layer and add join
                tmp_lyr = str(arcpy.MakeFeatureLayer_management(tmp, 'temp_for_join').getOutput(0))
                arcpy.AddJoin_management(tmp_lyr, tmp_field, rel_table, rel_field)
                arcpy.CopyFeatures_management(tmp_lyr, out_fc)

                # Clean up
                for t in [tmp, tmp_lyr]:
                    arcpy.Delete_management(t)
                arcpy.DeleteField_management(out_fc, [tmp_field])

                # Export results
                arcpy.AddMessage('Exported {0} Selected features '\
                                 'to: {1}'.format(int(arcpy.GetCount_management(out_fc).getOutput(0)), out_fc))

            else:                  
                # Join records and export to new feature class
                arcpy.AddJoin_management(in_ft, in_field, rel_table, rel_field)
                arcpy.CopyFeatures_management(in_ft, out_fc)
                arcpy.RemoveJoin_management(in_ft, rel_table)

                # Export results
                arcpy.AddMessage('Exported {0} Selected features '\
                                 'to: {1}'.format(int(arcpy.GetCount_management(out_fc).getOutput(0)), out_fc))

    # Zoom to selected features
    df.zoomToSelectedFeatures()
    arcpy.RefreshActiveView()
    return

if __name__ == '__main__':

    # Run it
    SelectRelatedRecords(*sys.argv[1:])
4
  • I have no luck with this script. Commented Apr 29, 2015 at 14:00
  • It works for me every time. This needs to be made into a script tool or you can run the function in the ArcMap Python window, but you need to pass in the parameters yourself. What error message do you get?
    – crmackey
    Commented Apr 29, 2015 at 14:11
  • What are the parameters that I need to pass? Commented Apr 30, 2015 at 5:00
  • The parameters are defined at the top of the function in the doc string. However, after seeing the post where this issue was addressed earlier, I would abandon this script. All you have to do is join your features to the related table using the "Keep only matching" option, and then use the Copy Features tool from the data management toolbox. That will automatically create duplicate features.
    – crmackey
    Commented Apr 30, 2015 at 13:38

Not the answer you're looking for? Browse other questions tagged or ask your own question.