[GIS] Copying dbf data into shapefile using ArcPy

arcpyattribute-joinsone-to-many

How do I perform a one-to-many join in a python script, from a dbf to a shapefile?

I saw (Greg Krakow's method) using QGIS, but I can't use it (I'm working on it, but QGIS is not yet recognize as an "official and usable" option within our organisation).

My dbf contains many records with the same ID and my source shapefile contains the geometry for each ID.

My approach is to create from scratch a shapefile ("outFile" in the script) by copying the structure of my dbf (adding field by field), using arcpy.FieldList()

dbfFieldList = arcpy.ListFields(dbf)

for field in dbfFieldList:
    fieldTypeShp = validFieldType(field.type)
    arcpy.AddField_management (outFile, field.name, fieldTypeShp, "", "", field.length)

validFieldType(field.type) is a function "converting" the field type of my dbf to a valid field type for arcpy. For example, I have a "smallint" which came back as "SHORT" so I could use AddField_management…

I figured that if I could read my dbf line by line, I could, field by field (since both my dbf and shp have the exact same structure), udpate the value of my shapefile.

#-- Seach cursor for my .dbf
searchCur = arcpy.SearchCursor(dbf)

for sCur in searchCur:

    #-- Insert cursor for my shapefile
    cur = arcpy.InsertCursor(outFile)
    row = cur.newRow()

    #-- Reading for the current row, the fields value, one by one.
    for field in dbfFieldList:
        fieldName = field.name
        val = sCur.getValue(fieldName)
        row.setValue(fieldName,val)

    #-- Inserting the new row into my shapefile
    cur.InsertRow(row) 

But I have an error executing the function "setValue". If I remove that line and the cur.InsertRow (or put a "print val" it works perfectly. I have created a shapefile with the same number of row as my dbf, but I can't add the field values.

After that part, I would use the ID field to retrieve the geometry from my source shapefile with the same ID, recreating my 1-to-many join.

If only I could make that part work.

Best Answer

You should be able to overcome the problem by adding in some error handling. Without the exact error message, I can only assume that you are running into issues with attempting to manually fill restricted fields such as OID, as @Jason pointed out. Try the following and see if this works out for you:

dbfFieldList = arcpy.ListFields(dbf)

for field in dbfFieldList:
    fieldTypeShp = validFieldType(field.type)
    try:
        arcpy.AddField_management (outFile, field.name, fieldTypeShp, "", "", field.length)
    except:
        print "Field, '" + field.name + "' cannot be added."

searchCur = arcpy.SearchCursor(dbf)
cur = arcpy.InsertCursor(outFile)

for sCur in searchCur:


    #-- Create a new row in the outfile
    row = cur.newRow()

    #-- Reading for the current row, the fields value, one by one.
    for field in dbfFieldList:
        val = sCur.getValue(field.name)
        try:
            row.setValue(field.name,val)
        except:
            print "Cannot populate field, '" + field.name + "'."

    #-- Inserting the new row into my shapefile
    cur.insertRow(row) 
Related Question