这个案例是前几天同事遇到的一个案例,在存储过程中“删除”了一个临时表,然后重新创建这个临时表时遇到“There is already an object named 'xxxx' in the database."这样的错误。下面简单演示一下这个案例(不用存储过程,而是直接用简单的SQL语句重现)

CREATE TABLE #temp_test( id INT, name VARCHAR(32));

 

 

IF  EXISTS (SELECT 1 FROM tempdb..sysobjects WHERE name='#tmp_test')

BEGIN

    DROP TABLE #temp_test;

END

GO

 

 

CREATE TABLE #temp_test( id INT, name VARCHAR(32));

同事很是不解,问我为什么在存储过程里面“删除”了这个临时表居然不能重建呢? 其实这里面并没有什么玄机,而是仅仅犯了逻辑错误。上面这个SQL语句,其实永远也不会删除这个临时表。

原因很简单,临时表#temp_test在tempdb..sysobjects里面存储的名字为“#temp_test_________________________________________________________________0000000000EE”,所以上述脚本犯了一个逻辑错误: 开发人员以为临时表被删除了,其实实质上永远不会执行DROP TABLE #temp_test这句SQL。存储在tempdb的sysobjects表中的临时表,其全名由 CREATE TABLE 语句中指定的表名和系统生成的数字后缀组成。为了允许追加后缀,为本地临时表指定的table_name不能超过 116 个字符(关于为什么是116字符,也是有原因的,此处不展开)

Both regular and delimited identifiers must contain from 1 through 128 characters. For local temporary tables, the identifier can have a maximum of 116 characters.

那么为什么数据库自动会给临时表这样命名呢? 因为本地临时表是对当前连接(当前会话)可见的。但是任意会话都可以创建同样名字的临时表,那么临时表的元数据在数据库内部存储的时候,使用同样的名字就不能定位和区别,所以设计上,为了区别不同会话下同样命名的临时表,在tempdb..sysobjects里面临时表会保存的是数据库自动生成的名字(#临时表名+下划线+12位的十六进制字符),如下测试所示,在另外一个会话中,我们创建一个同样名字的临时表,然后我们去数据库检查,你会发现tempdb..sysobjects中有两个对象,他们名字的后缀是不一样的。

SELECT @@SPID;

GO

CREATE TABLE #temp_test( id INT, name VARCHAR(32));

那么要如何定位、查找当前会话是否创建了本地临时表对象呢? 其实使用OBJECT_ID函数就OK了:

IF OBJECT_ID('tempdb..#temp_test' ) IS NOT NULL DROP TABLE #temp_test;

那么存储过程中使用上述脚本删除本地临时表,然后重建同样名字的临时表就可以了吗? 事实告诉我们,虽然上面SQL可以找到当前会话创建的本地临时表删除,但是如果是在存储过程里面,使用这种方式,创建本地临时表,然后删除、创建,依然会遇到这个错误,如下测试所示:

CREATE PROCEDURE PRC_TEST

AS

BEGIN 

 

    IF OBJECT_ID('tempdb..#temp_test' ) IS NOT NULL DROP TABLE #temp_test;

    CREATE TABLE #temp_test( id INT, name VARCHAR(32));

 

    INSERT INTO #temp_test VALUES(10, 'jimmy');

 

    IF OBJECT_ID('tempdb..#temp_test' ) IS NOT NULL DROP TABLE #temp_test;

 

    CREATE TABLE #temp_test( id INT, name VARCHAR(32));

 

    INSERT INTO #temp_test VALUES(100, 'kerry');

 

 

    DROP TABLE #temp_test;

END

GO

其实在一个批处理里面执行下面SQL语句也会报错,但是改写一下SQL,在删除后面加上一个GO语句,那么这样是不会报错的(但是你单个SQL,一条一条执行是不会报错的).

CREATE TABLE #temp_test( id INT, name VARCHAR(32));

INSERT INTO #temp_test VALUES(10, 'jimmy');

IF OBJECT_ID('tempdb..#temp_test' ) IS NOT NULL DROP TABLE #temp_test;

CREATE TABLE #temp_test( id INT, name VARCHAR(32));

INSERT INTO #temp_test VALUES(100, 'kerry');

DROP TABLE #temp_test;

至于原因是什么呢?网上有种分析是因为解析错误(parse error),这里我也倾向于这种说法,因为测试过程中,发现其实上面SQL语句报错,但是实质上,本地临时表已经在tempdb被删除了。加上一个GO这种改写方法,其实使用两个批处理,下面这样的SQL是不会报错的。

CREATE TABLE #temp_test( id INT, name VARCHAR(32));

INSERT INTO #temp_test VALUES(10, 'jimmy');

IF OBJECT_ID('tempdb..#temp_test' ) IS NOT NULL DROP TABLE #temp_test;

  GO

CREATE TABLE #temp_test( id INT, name VARCHAR(32));

INSERT INTO #temp_test VALUES(100, 'kerry');

DROP TABLE #temp_test;

参考资料:

https://blog.sqlauthority.com/2012/05/01/sql-server-maximum-allowable-length-of-characters-for-temp-objects-is-116-guest-post-by-balmukund-lakhani/

https://blogs.msdn.microsoft.com/sqlserverfaq/2012/03/15/an-interesting-find-about-temp-tables-in-sql-server/

There is already an object named '#xxxx' in the database.的更多相关文章

  1. mybatis There is no getter for property named 'xxxx

    mybatis There is no getter for property named 'xxxx 360反馈意见截图16230322799670.png http://blog.sina.com ...

  2. python3命令行ImportError: No module named 'xxxx'的问题

    主要原因:启动脚本不在当前目录下,无法找到上一层 在pycharm写好的脚本程序,在命令行无法运行,报错 Traceback (most recent call last): File "t ...

  3. python中类的输出或类的实例输出为何是<__main__类名 object at xxxx>这种形式?

    原因: __str__()这个特殊方法将对象转换为字符串的结果 效果图: 代码: # 定义一个Person类 class Person(object): """人类&qu ...

  4. 问题: 刚安装的PyCharm执行代码报“ModuleNotFoundError: No module named XXXX”错

    老猿刚安装好PyCharm后,直接新建了一个工程文件并导入了一个已有的爬虫程序文件,该文件原来在Python解释器下能执行,但在PyCharm下执行时报错: F:\学习\python\SRC\proj ...

  5. #!/usr/bin/python3的作用 解决vscode ImportError: No module named xxxx

    在 Python 脚本的第一行经常见到这样的注释: #!/usr/bin/env python3 或者 #!/usr/bin/python3 含义 在脚本中, 第一行以 #! 开头的代码, 在计算机行 ...

  6. 命令行运行python项目文件,报错:ModuleNotFoundError: No module named 'xxxx' 解决办法

    在pycharm中写好了自动化测试脚本,并能在pycharm中正常运行,由于要考虑到无人值守时能自动执行,执行时就需要脱离pycharm,直接能用命令执行.但是直接用命令执行用例文件:python3 ...

  7. 【Entity Framework】disable automatic migration, 执行update-migration仍然会显示有automatic migration

    本文涉及的相关问题,如果你的问题或需求有与下面所述相似之处,请阅读本文 [Entity Framework] disable automatic migration, 执行update-migrati ...

  8. MVC5 网站开发之七 用户功能 1、角色的后台管理

    角色是网站中都有的一个功能,用来区分用户的类型.划分用户的权限,这次实现角色列表浏览.角色添加.角色修改和角色删除. 目录 奔跑吧,代码小哥! MVC5网站开发之一 总体概述 MVC5 网站开发之二 ...

  9. Constraint2:constraint

    一,Constraint 是表定义的一部分,用于实现数据完整性. Data Integrity 由三种类型的constraint实现: Entity Integrity:数据是唯一的.约束: prim ...

随机推荐

  1. 浅谈java线程池实现

    再进入主题之前,我们先了解几个概念,对读源码有所帮助,对于线程池的运行状态,有4个级别,分别是RUNNING,SHUTING,STOP,TIDING,TERMINATED 解释如下: The runS ...

  2. 瑞芯微发布最新旗舰应用处理器-RK3588

    在瑞芯微电子第四届“开发者之春”大会上,瑞芯微推出了新一代8nm旗舰处理器-RK3588 这个芯片将采用8nm 制程工艺.基于A76+A55 内核组合,具备4K UI性能.8K VPU,拥有NPU2. ...

  3. crontab常用

    --crontab检查是否安装[oracle@rac1 ~]$ rpm -qa | grep crontabcrontabs-1.10-8启动与关闭[oracle@rac1 ~]$ /etc/init ...

  4. Gaussian Mixture Models and the EM algorithm汇总

    Gaussian Mixture Models and the EM algorithm汇总 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 1. 漫谈 ...

  5. 快速构建SPA框架SalutJS--项目工程目录 三

    配置文件 在开始我们的第一个界面之前,我们需要把初始的html和config文件配置好.html非常简单,只需要一个div作为最外部的容器包裹着所有界面即可: <!DOCTYPE html> ...

  6. 解决Ajax请求时无法重定向的问题

    今天发现,当使用Ajax请求时,如果后台进行重定向到其他页面时是无法成功的,只能在浏览器地址栏输入才能够实现重定向. Ajax默认就是不支持重定向的,它是局部刷新,不重新加载页面. 需要实现的功能是, ...

  7. [Swift-2019力扣杯春季决赛]4. 有效子数组的数目

    给定一个整数数组 A,返回满足下面条件的 非空.连续 子数组的数目: 子数组中,最左侧的元素不大于其他元素. 示例 1: 输入:[1,4,2,5,3] 输出:11 解释:有 11 个有效子数组,分别是 ...

  8. Google File System 见解 (作业)

    Google File System ——见解 近年来,大街小巷都传遍的大数据,引起了社会的一阵学习大数据狂热,造成任何公司在招聘人员的时候都会注上一条,会大数据的优先考虑:但是,从另一方面来说,这狂 ...

  9. [.NET跨平台]Jexus独立版本的便利与过程中的一些坑

    本文环境与前言 之前写过一篇相关的文章:在.NET Core之前,实现.Net跨平台之Mono+CentOS+Jexus初体验 当时的部署还是比较繁琐的,而且需要联网下载各种东西..有兴趣的可以看看, ...

  10. 死磕 java集合之ConcurrentSkipListMap源码分析——发现个bug

    前情提要 点击链接查看"跳表"详细介绍. 拜托,面试别再问我跳表了! 简介 跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表. 跳表在原有的有序链表上面增加了多级 ...