Select by attribute use cursor save off as feature class

3885
17
02-18-2014 10:39 AM
MikePowell
New Contributor II
I feel this is a very basic problem but for the life of me I can't seem to figure out what is wrong, which is driving mad. I am assuming it is my logic. I have a feature class with hundreds of polygons. I figured I could make a layer file, use a search cursor to select each polygon and save each one off as it's own feature class. I seem to always get an error that the dataset xxxxx does not exist or is not supported when trying to do Copy Feature.  Here is what I have:

import sys, string, os, cx_Oracle, arcpy, datetime

arcpy.env.workspace = "c:\\work\\scripting\\test\\testdata.gdb"
arcpy.MakeFeatureLayer_management("rsids","rsid_view")
rows = arcpy.SearchCursor("rsid_view","","","NUM; EXTENSION","NUM A")
row = rows.next()
while row:
    RSIDNum = str(row.getValue("NUM"))
    Ext = str(row.getValue("EXTENSION"))
    if Ext == "None":
        Ext = ""
    rsid = RSIDNum+Ext
    RSID = "RSID"+RSIDNum+Ext
    arcpy.CopyFeatures_management(RSID, "c:\\work\\scripting\\test\\testdata.gdb\\"+RSID)
    row - rows.next()
del row
del rows
if arcpy.Exists("rsid_view"):
   arcpy.Delete_management("rsid_view")
   print "View deleted"


I have tried using Select by attribute first (before the search cursor) but that almost seems redundant, and I get the same problem anyway. Any help will be appreciated. Thanks in advance
Tags (2)
0 Kudos
17 Replies
JoshuaChisholm
Occasional Contributor III
Hello Mike,

A few notes:

  1. First off, you have change the row - rows.next() to row = rows.next() (in the while loop).

  2. Second, check your field name "NUM A" can't be a field name since it has a space.

  3. Third, I would actually change the while loop to a for loop (and get rid of both row = rows.next() lines). This would negate the first comment. I find for loops generally easier to grasp and less problematic.

  4. Forth, I would use the Feature Class To Feature Class tool. It has a built in where clause that would allow you to only export one record at a time.


I would use something like this:
import arcpy
arcpy.env.workspace = "C:\\work\\scripting\\test\\testdata.gdb"
fc="rsid"
outLocation="C:\\work\\scripting\\test\\output"
rows = arcpy.SearchCursor(fc,"","","NUM; EXTENSION","NUM A")
for row in rows:
    where='"FID" = '+str(row.NUM) #Note that the given field must be unique, also assumes field is a number type. We'll have to make a new where statement if NUM is a string/text
    arcpy.FeatureClassToFeatureClass_conversion(fc, outLocation, str(row.NUM), where)
del row
del rows


Let me know how it goes, we'll figure it out!
0 Kudos
MikePowell
New Contributor II
Thanks for the quick reply. I will just go off your steps:

1. Yep, that was a type-o.
2. NUM A is not field name. It is an attribute of the SearchCursor where I am sorting on the field name NUM. NUM and EXTENSION are the two field names.
3. I have tried the "for loop" as well. with no success.
4. I like the use of the Feature Class to Feature Class. I tried that once but I couldn't get it to work.

I ran what you provided, this is what I got:

ExecuteError: ERROR 000361: The name starts with an invalid character
Failed to execute (FeatureClassToFeatureClass).

I know that NUM is set up as a string but they are all numbers and isn't that an issue when naming a feature class. That is why I had that other code in there to merge the field names and add "RSID" in front of it. I went ahead and tried this:

arcpy.FeatureClassToFeatureClass_conversion(fc, outLocation, "r"+str(row.NUM), where)


that seemed to work until it got to a duplicate. That is why I have a Select by Layer to eliminate those duplicates:

arcpy.SelectLayerByAttribute_management("rsid_view", "NEW_SELECTION", """"EXTENSION" not like 'X%' AND "EXTENSION" <> 'x'""")
arcpy.SelectLayerByAttribute_management("rsid_view", "ADD_TO_SELECTION", """"NUM" = '783'""")


I guess I just answered my own thoughts about it being redundant with the SearchCursor. Any thoughts? Can you use FeatureClassToFeatureClass with a MakeFeatureLayer? I also noticed that the feature classes that it did make, were named correctly but the attributes were not correct on any of them and some didn't have any. Appreciate any other thoughts you might have. Thanks again in advance
0 Kudos
JoshuaChisholm
Occasional Contributor III
Hello Mike,

Regarding item 2: my apologies, you're right. Also, nice fix on the error!

Regarding the where clause:
If NUM is actually set up as a string, you'll need to change the where expression to:
where='"NUM" = \''+str(row.NUM)+'\''

However, I guess if you got it working then you should leave it as is!

Regarding the duplicate issue, it depends on how you want to handle them. I assume you sorted the records and you only want to take the first unique record.

Assuming your dataset isn't absurdly large, I would create an array of all NUM's you've processed and then only create a new FC if the current NUM isn't in the processed NUM array. Like this:
import arcpy
arcpy.env.workspace = "C:\\work\\scripting\\test\\testdata.gdb"
fc="rsid"
outLocation="C:\\work\\scripting\\test\\output"
rows = arcpy.SearchCursor(fc,"","","NUM; EXTENSION","NUM A")
processedNUMs=[]
for row in rows:
    num=str(row.NUM)
    if num in processedNUMs:
        continue
    where='"NUM" = '+num #if NUM is a number
    #where='"NUM" = \''+num+'\'' #if NUM is a string/text
    if row.EXTENSION == "None":
        ext=""
    else:
        ext=str(row.EXTENSION)
    newFCName="RSID"+num+ext
    arcpy.FeatureClassToFeatureClass_conversion(fc, outLocation, newFCName, where)
    processedNUMs.append(num)
del row
del rows
0 Kudos
MikePowell
New Contributor II
Nice! here is the final code that worked:

import arcpy
arcpy.env.workspace = "C:\\work\\scripting\\test\\testdata.gdb"
fc="rsids"
outLocation="C:\\work\\scripting\\test\\results.gdb"
rows = arcpy.SearchCursor(fc,"","","NUM; EXTENSION","NUM A")
processedNUMs=[]
for row in rows:
    num=str(row.NUM)
    if num in processedNUMs:
        continue
    #where='"NUM" = '+num #if NUM is a number
    where='"NUM" = \''+num+'\'' #if NUM is a string/text
    if row.EXTENSION == "None":
        ext=""
    else:
        ext=str(row.EXTENSION)
    newFCName="RSID"+num+ext
    arcpy.FeatureClassToFeatureClass_conversion(fc, outLocation, newFCName, where)
    processedNUMs.append(num)
del row
del rows


I had to make a couple of minor changes but it worked. I wasn't thinking array. Dictionary came up but wasn't sure about that. The only problem now, which I just found out after running this, is that in the attribute table, it isn't consist in the order how things were put in. If you notice in my Select Layer by Attributes, I was eliminating those with the EXTENSION = X (because those are duplicates of another with the same NUM but different EXTENSION but I don't want the ones with EXTENSION = X). After running your script, I found that some of those were ahead of the ones I wanted so it was doing those instead of the ones I wanted. Thank you so much for the help. If you have any ideas of having them skip the ones with EXTENSION = X that would be great. I will be working on that as well. I am thinking some kind of "if" statement running through the array? I'm just happy that it is working. Thanks again
0 Kudos
JoshuaChisholm
Occasional Contributor III
Hello Mike,

I'm happy to hear we're on the right track. As I understand it (please correct me if I'm wrong), you want to skip over any records that has an extension starting with the character 'x', or if the extension is simple 'x'. I'll also assume you want to skip the record regardless of case ('x' vs 'X').

If this is all correct, add these lines (just before the line newFCName="RSID"+num+ext😞
if ext.lower().startswith('x'):
    continue

Note this will also skip records if the extension is simple 'x' or 'X'. If you want to be case sensitive, remove .lower() and change 'x' to 'X' if desired.

Let me know how it goes!
0 Kudos
MikePowell
New Contributor II
That was the ticket. Thanks for all the help. There is a lot more to this script that I am working on, but I will be able to incorporate this into it and get that much closer to finishing it. It is possible that I will be on the forum again soon but I try to use it as a last resort and try to figure it out first on my own. I feel I understand more than the basics but I have a problem putting it all together in script form. I can read scripts a lot better than I can write them. Thanks again
0 Kudos
JoshuaChisholm
Occasional Contributor III
Good. I'm happy we fixed this part of your script. Your coding looks pretty good, you just need to keep learning the small tricks. I hope you get your master script working, but i'll keep an eye out (on this thread or a new one) in case you hit any brick walls.

Good luck, have fun!
0 Kudos
MikePowell
New Contributor II
Thanks, I appreciate it.

There is one last thing that has come up. There is one, where EXTENSION = <Null>. Everything works but it is still naming the feature class "RSID"+num+ext where ext is None (ex. RSID783None). There is a catch for it but it doesn't seem to be blanking it out. My guess is it isn't understanding the <Null>. I would like it to look like this, RSID783. Any thoughts?
0 Kudos
JoshuaChisholm
Occasional Contributor III
In python null values are stored as None (which is different form a string set to "None"). None is a keyword in python. You can type x=None into python. When you convert None to a string (str(None)) it prints "None" which is kind of confusing. If it printed an empty string ("") it might be more accurate.

Change this line if row.EXTENSION == "None": to:
if row.EXTENSION == "None" or row.EXTENSION==None:


This would also work, but it's kind of confusing, so I would not use it:
if str(row.EXTENSION) == "None":


Let me know if it gives you any problems.
0 Kudos