使用ArcPy将ArcSDE地理数据库复制到文件地理数据库?


9

我想将SDE数据库的精确副本(域,要素数据集,要素类等)复制到文件地理数据库中。

我尝试了几种可能性,包括:

  1. 使用复制(数据管理)过程
  2. 创建一个新的GDB并从SDE手动复制每个要素数据集
  3. 从SDE导出xml工作区文档并将其导入到GDB中

Copy_management过程似乎不适用于将SDE复制到GDB,因为输入和输出数据类型必须匹配。

将每个要素数据集导入新GDB的过程可能也可以使用Copy_management通过遍历每个要素数据集来自动执行,尽管如果其中一个过程出现错误,这似乎可能会导致复制不完整的问题。

导出和导入xml工作区似乎可行,尽管当在大型地理数据库上使用该过程时,该过程会创建非常大的文件。

是否有比上述方式更简单的方式可以将SDE的内容和模式复制到GDB,并且可以自动进行?

如果不是,是否有任何理由不应在此过程中使用上述可能性?


Answers:


5

获得数据(域,数据集,关系等)真实副本的唯一方法是在目录内部使用手动复制和粘贴方法。ESRI尚未使我们能够通过易于编写脚本的单个操作以任何其他方式传输此数据。

我有一个每晚执行的过程,将两个主SDE数据库复制到文件地理数据库中,以确保操作的连续性。这样一来,在紧急情况下,我的员工就可以使用一些数据,直到我的IT商店可以从备份中重建SDE。经过反复试验,我决定我们可以忍受使用FeatureClassToFeatureClass_conversionTableToTable_conversion在每天晚上传输数据的局限性。

是的,我们失去了地理数据库的某些功能,但现在它将在夜间无人值守运行,并且一旦我获得它就可以开始使用。在我的情况下,我们真正缺少的唯一功能(假设在紧急模式下运行)是我的关系类已损坏,因为该转换会重置链接两个表的ObjectID。

在ESRI为我们提供更多选择之前,您必须先了解一下您目前愿意付出的代价;时间和精力或功能?


xml Worskspace文档无法正常工作?
耶勒2016年

8

我知道这篇文章有些旧,但是我会分享我的答案,因为我也遇到了同样的问题。以下脚本应该复制不在数据集中的所有表,要素类和关系,并且还将在所有数据集上进行复制,包括数据集中的要素类,拓扑等。在复制和继续操作期间,它将跳过所有错误。它将生成一个日志文件,其中包含诸如源DB项目计数和目标项目计数之类的数据,因此您可以比较副本,并且还将记录遇到的错误。

import arcpy, os, shutil, time
import logging as log
from datetime import datetime

def formatTime(x):
    minutes, seconds_rem = divmod(x, 60)
    if minutes >= 60:
        hours, minutes_rem = divmod(minutes, 60)
        return "%02d:%02d:%02d" % (hours, minutes_rem, seconds_rem)
    else:
        minutes, seconds_rem = divmod(x, 60)
        return "00:%02d:%02d" % (minutes, seconds_rem)

def getDatabaseItemCount(workspace):
    arcpy.env.workspace = workspace
    feature_classes = []
    for dirpath, dirnames, filenames in arcpy.da.Walk(workspace,datatype="Any",type="Any"):
        for filename in filenames:
            feature_classes.append(os.path.join(dirpath, filename))
    return feature_classes, len(feature_classes)

def replicateDatabase(dbConnection, targetGDB):
    startTime = time.time()

    featSDE,cntSDE = getDatabaseItemCount(dbConnection)
    featGDB,cntGDB = getDatabaseItemCount(targetGDB)

    now = datetime.now()
    logName = now.strftime("SDE_REPLICATE_SCRIPT_%Y-%m-%d_%H-%M-%S.log")
    log.basicConfig(datefmt='%m/%d/%Y %I:%M:%S %p', format='%(asctime)s %(message)s',\
    filename=logName,level=log.INFO)

    print "Old Target Geodatabase: %s -- Feature Count: %s" %(targetGDB, cntGDB)
    log.info("Old Target Geodatabase: %s -- Feature Count: %s" %(targetGDB, cntGDB))
    print "Geodatabase being copied: %s -- Feature Count: %s" %(dbConnection, cntSDE)
    log.info("Geodatabase being copied: %s -- Feature Count: %s" %(dbConnection, cntSDE))

    arcpy.env.workspace = dbConnection

    #deletes old targetGDB
    try:
        shutil.rmtree(targetGDB)
        print "Deleted Old %s" %(os.path.split(targetGDB)[-1])
        log.info("Deleted Old %s" %(os.path.split(targetGDB)[-1]))
    except Exception as e:
        print e
        log.info(e)

    #creates a new targetGDB
    GDB_Path, GDB_Name = os.path.split(targetGDB)
    print "Now Creating New %s" %(GDB_Name)
    log.info("Now Creating New %s" %(GDB_Name))
    arcpy.CreateFileGDB_management(GDB_Path, GDB_Name)

    datasetList = [arcpy.Describe(a).name for a in arcpy.ListDatasets()]
    featureClasses = [arcpy.Describe(a).name for a in arcpy.ListFeatureClasses()]
    tables = [arcpy.Describe(a).name for a in arcpy.ListTables()]

    #Compiles a list of the previous three lists to iterate over
    allDbData = datasetList + featureClasses + tables

    for sourcePath in allDbData:
        targetName = sourcePath.split('.')[-1]
        targetPath = os.path.join(targetGDB, targetName)
        if arcpy.Exists(targetPath)==False:
            try:
                print "Atempting to Copy %s to %s" %(targetName, targetPath)
                log.info("Atempting to Copy %s to %s" %(targetName, targetPath))
                arcpy.Copy_management(sourcePath, targetPath)
                print "Finished copying %s to %s" %(targetName, targetPath)
                log.info("Finished copying %s to %s" %(targetName, targetPath))
            except Exception as e:
                print "Unable to copy %s to %s" %(targetName, targetPath)
                print e
                log.info("Unable to copy %s to %s" %(targetName, targetPath))
                log.info(e)
        else:
            print "%s already exists....skipping....." %(targetName)
            log.info("%s already exists....skipping....." %(targetName))
    featGDB,cntGDB = getDatabaseItemCount(targetGDB)
    print "Completed replication of %s -- Feature Count: %s" %(dbConnection, cntGDB)
    log.info("Completed replication of %s -- Feature Count: %s" %(dbConnection, cntGDB))
    totalTime = (time.time() - startTime)
    totalTime = formatTime(totalTime)
    log.info("Script Run Time: %s" %(totalTime))

if __name__== "__main__":
    databaseConnection = r"YOUR_SDE_CONNECTION"
    targetGDB = "DESTINATION_PATH\\SDE_Replicated.gdb"
    replicateDatabase(databaseConnection, targetGDB)   

我真的很幸运。我正在将SDE数据库复制到文件地理数据库。尽管此脚本可以满足我的所有需求,但我并未对其进行过多的测试。我使用ArcGIS 10.3对其进行了测试。另外,需要注意的一件事是,我正在与使用此脚本的人进行交谈,由于权限不正确和表空,他们在复制某些数据集时遇到了问题。

狐猴-为什么不基于全局ID而不是对象ID创建关系?保证您的人际关系得到保留。如果您尚未创建全局ID,则强烈建议您使用。

-更新

我在代码中添加了一些逻辑以处理错误的数据库连接路径以及更好的日志记录和错误处理:

import time, os, datetime, sys, logging, logging.handlers, shutil
import arcpy

########################## user defined functions ##############################

def getDatabaseItemCount(workspace):
    log = logging.getLogger("script_log")
    """returns the item count in provided database"""
    arcpy.env.workspace = workspace
    feature_classes = []
    log.info("Compiling a list of items in {0} and getting count.".format(workspace))
    for dirpath, dirnames, filenames in arcpy.da.Walk(workspace,datatype="Any",type="Any"):
        for filename in filenames:
            feature_classes.append(os.path.join(dirpath, filename))
    log.info("There are a total of {0} items in the database".format(len(feature_classes)))
    return feature_classes, len(feature_classes)

def replicateDatabase(dbConnection, targetGDB):
    log = logging.getLogger("script_log")
    startTime = time.time()

    if arcpy.Exists(dbConnection):
        featSDE,cntSDE = getDatabaseItemCount(dbConnection)
        log.info("Geodatabase being copied: %s -- Feature Count: %s" %(dbConnection, cntSDE))
        if arcpy.Exists(targetGDB):
            featGDB,cntGDB = getDatabaseItemCount(targetGDB)
            log.info("Old Target Geodatabase: %s -- Feature Count: %s" %(targetGDB, cntGDB))
            try:
                shutil.rmtree(targetGDB)
                log.info("Deleted Old %s" %(os.path.split(targetGDB)[-1]))
            except Exception as e:
                log.info(e)

        GDB_Path, GDB_Name = os.path.split(targetGDB)
        log.info("Now Creating New %s" %(GDB_Name))
        arcpy.CreateFileGDB_management(GDB_Path, GDB_Name)

        arcpy.env.workspace = dbConnection

        try:
            datasetList = [arcpy.Describe(a).name for a in arcpy.ListDatasets()]
        except Exception, e:
            datasetList = []
            log.info(e)
        try:
            featureClasses = [arcpy.Describe(a).name for a in arcpy.ListFeatureClasses()]
        except Exception, e:
            featureClasses = []
            log.info(e)
        try:
            tables = [arcpy.Describe(a).name for a in arcpy.ListTables()]
        except Exception, e:
            tables = []
            log.info(e)

        #Compiles a list of the previous three lists to iterate over
        allDbData = datasetList + featureClasses + tables

        for sourcePath in allDbData:
            targetName = sourcePath.split('.')[-1]
            targetPath = os.path.join(targetGDB, targetName)
            if not arcpy.Exists(targetPath):
                try:
                    log.info("Atempting to Copy %s to %s" %(targetName, targetPath))
                    arcpy.Copy_management(sourcePath, targetPath)
                    log.info("Finished copying %s to %s" %(targetName, targetPath))
                except Exception as e:
                    log.info("Unable to copy %s to %s" %(targetName, targetPath))
                    log.info(e)
            else:
                log.info("%s already exists....skipping....." %(targetName))

        featGDB,cntGDB = getDatabaseItemCount(targetGDB)
        log.info("Completed replication of %s -- Feature Count: %s" %(dbConnection, cntGDB))

    else:
        log.info("{0} does not exist or is not supported! \
        Please check the database path and try again.".format(dbConnection))

#####################################################################################

def formatTime(x):
    minutes, seconds_rem = divmod(x, 60)
    if minutes >= 60:
        hours, minutes_rem = divmod(minutes, 60)
        return "%02d:%02d:%02d" % (hours, minutes_rem, seconds_rem)
    else:
        minutes, seconds_rem = divmod(x, 60)
        return "00:%02d:%02d" % (minutes, seconds_rem)

if __name__ == "__main__":
    startTime = time.time()
    now = datetime.datetime.now()

    ############################### user variables #################################
    '''change these variables to the location of the database being copied, the target 
    database location and where you want the log to be stored'''

    logPath = ""
    databaseConnection = "path_to_sde_or_gdb_database"
    targetGDB = "apth_to_replicated_gdb\\Replicated.gdb"

    ############################### logging items ###################################
    # Make a global logging object.
    logName = os.path.join(logPath,(now.strftime("%Y-%m-%d_%H-%M.log")))

    log = logging.getLogger("script_log")
    log.setLevel(logging.INFO)

    h1 = logging.FileHandler(logName)
    h2 = logging.StreamHandler()

    f = logging.Formatter("[%(levelname)s] [%(asctime)s] [%(lineno)d] - %(message)s",'%m/%d/%Y %I:%M:%S %p')

    h1.setFormatter(f)
    h2.setFormatter(f)

    h1.setLevel(logging.INFO)
    h2.setLevel(logging.INFO)

    log.addHandler(h1)
    log.addHandler(h2)

    log.info('Script: {0}'.format(os.path.basename(sys.argv[0])))

    try:
        ########################## function calls ######################################

        replicateDatabase(databaseConnection, targetGDB)

        ################################################################################
    except Exception, e:
        log.exception(e)

    totalTime = formatTime((time.time() - startTime))
    log.info('--------------------------------------------------')
    log.info("Script Completed After: {0}".format(totalTime))
    log.info('--------------------------------------------------')

彼得,我使用了您提供的脚本,并更新了底部的2个变量。我收到错误回溯(最近一次通话最近):<模块>复制数据库(databaseConnection,targetGDB)中的文件“ ServerPath \\ CopySDEtoGDB.py”,行90,文件中的“ ServerPath \\ CopySDEtoGDB.py”,行55,复制数据数据库数据集列表= [arcpy.ListDatasets()中的arcpy.Describe(a).name] TypeError:'NoneType'对象不可迭代任何线索这意味着什么?
Courtney

Courtney-听起来您的数据库连接变量的路径中有错别字或轻微错误。它抛出错误是因为它试图遍历第55行上为空的列表。通过使用“ databaseConnection”变量中的错误路径,我能够重新创建错误。您在变量中使用的实际路径是什么?
PMK 2015年

如果我想每晚进行此操作,它将不会覆盖现有功能?我不想每次只想覆盖现有目标时都创建一个新的FGD。
NULL.Dude17年

彼得,如果目标GDB存在,脚本将失败
NULL.Dude17年

2

我使用了类似于Peter上面的脚本,虽然他的脚本更好,但也很幸运。需要指出的一件事是,如果您使用的是64位python地理处理,并且已将ArcFM加载到ESRI之上,则设置为使用ArcFM或Designer且错误为000260的所有功能都将失败。是因为您必须使用32位python,否则ArcFM内容将无法正确授权。

有关使用32位ArcPy的详细说明,请参阅Exchange中有关此线程的前两个注释。

https://infrastructurecommunity.schneider-electric.com/docs/DOC-2563


如果这两个评论提供了该问题的答案,那么它们的内容应该在此处引用或摘要,而不仅仅是链接到-请参见meta.stackexchange.com/questions/225370/… 如果您已经提供了摘要,则也许只需更改“检查删除有关此线程在Exchange中的前两个注释”到“有关详细说明,请参阅有关此线程在Exchange中的前两个注释”。
PolyGeo

0

如果您具有管理员权限,则可以使用简单的复制和粘贴命令将sde导出或导入到文件地理数据库,反之亦然,请查看此处了解更多详细信息。


感谢Ganeshnarim-我想使用Python自动化该过程,因此ArcCatalog中的任何手动复制/粘贴过程都不符合我的需求。我在此方法上也取得了有限的成功,因为似乎(在ArcMap 10.1中)复制SDE只会创建到同一数据库的另一个链接(而如果在文件或个人地理数据库上使用了相同的技术,则会进行复制)
Krausers 2013年
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.