SQL Server临时表主键报错:已存在对象'PK_temp'的解决咨询
临时表主键重复报错问题排查与解决
报错信息:
There is already an object named 'PK_temp' in the database.
我通过Python将数据上传至SQL Server临时表,使用后删除该表,但每次重新运行代码都会触发上述报错。我原本以为删除临时表时,其关联的主键会自动被删除,对此感到困惑。
具体操作步骤
步骤1:删除已存在的临时表
run_sql("""IF OBJECT_ID (N'tempdb..#temp') IS NOT NULL drop table #temp""", engine)
步骤2:创建带主键的临时表并通过XML上传数据
query = """ set nocount on; declare @temp varchar(max); select @temp = '{xml_str}'; -- CREATE TEMP TABLES CREATE TABLE #temp( id int not null, CONSTRAINT PK_temp PRIMARY KEY (id asc), ); -- EXTRACT XML INTO TEMP TABLES declare @xml xml declare @hdoc int; select @xml = @temp exec sp_xml_preparedocument @hdoc OUTPUT, @xml insert into #temp (id) select id from OPENXML(@hdoc, '/data/row', 2) with (id int) exec sp_xml_removedocument @hdoc; """.format(xml_str = id_xml_str) run_sql(query, engine)
自定义run_sql函数
def run_sql(sql, engine): session = Session(engine) try: session.execute(clause=sql) session.commit() except Exception as e: session.rollback() raise e finally: session.close() return
id_xml_str示例
" <data> <row> <index>0</index> <id>18511</id> </row> <row> <index>1</index> <id>18671</id> </row> <row> <index>2</index> <id>18711</id> </row> <row> <index>3</index> <id>18833</id> </row> <row> <index>4</index> <id>18965</id> </row> </data>"
使用环境
python==3.7 sqlalchemy==1.3.20
报错原因
SQL Server的tempdb中,约束名称是全局唯一的。你显式指定了主键约束名PK_temp,如果之前的会话未完全释放资源(比如连接池复用的连接中残留了约束元数据),或者步骤1和步骤2使用了不同的数据库连接(SQLAlchemy连接池默认复用连接),再次创建同名约束就会触发冲突。
另外,本地临时表(#开头)是会话级的,但跨连接执行删除和创建操作时,不同会话的临时表相互独立,步骤1在连接A中删除的临时表,不影响连接B中可能存在的同名临时表,此时在连接B中创建带同名约束的表就会报错。
解决方法
方法1:让SQL Server自动生成主键约束名(推荐)
去掉显式的约束命名,让系统自动生成唯一名称,避免冲突:
CREATE TABLE #temp( id int not null PRIMARY KEY (id asc) );
或者简化写法:
CREATE TABLE #temp( id int not null, PRIMARY KEY (id asc) );
方法2:在同一会话中执行删除与创建操作
将步骤1和步骤2合并到同一个SQL脚本中,确保在同一个数据库连接内完成删除和创建,避免跨连接的资源残留问题:
query = """ IF OBJECT_ID (N'tempdb..#temp') IS NOT NULL drop table #temp; set nocount on; declare @temp varchar(max); select @temp = '{xml_str}'; -- CREATE TEMP TABLES CREATE TABLE #temp( id int not null, CONSTRAINT PK_temp PRIMARY KEY (id asc), ); -- EXTRACT XML INTO TEMP TABLES declare @xml xml declare @hdoc int; select @xml = @temp exec sp_xml_preparedocument @hdoc OUTPUT, @xml insert into #temp (id) select id from OPENXML(@hdoc, '/data/row', 2) with (id int) exec sp_xml_removedocument @hdoc; """.format(xml_str = id_xml_str) run_sql(query, engine)
内容的提问来源于stack exchange,提问作者dhs4402
相关产品推荐
相关产品推荐

