使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?

时间:2022-11-19 20:48:59
大家好!最近在实现将数据实时存入数据库的功能,大概思路是每1000行数据存入一个表,每500行进行一次批量存入操作。数据库中的表不是一次性创建的,当一个表存满1000行后,会重新创建一个表。表名为Table1,Table2,Table3~,仅有的区别在于后面的序号。
然后遇到一个很奇怪的问题,我使用以下代码创建表:
string sqlStr="if not exists(select * from sysobject where name='"+TableName+"') create Table "+TableName+"(id int primary key,count1 int not null,count2 int not null);
SqlCommand cmd=new SQLCommand(sql,conn);
cmd.ExecuteNonQuery();

为什么在创建第345个表时提示“用户代码未处理sqlException,数据库中已存在名为‘Table345’的对象”;按理说,在创建表前,我已经先判断了这个表是否存在,存在则不创建,为什么还会出现这个问题?而且,也不是每次创建都会出现这个问题,这次都第345个表了 使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?求指点。
PS:我测试了2次,这个bug是偶发性的,还有次是在创建第5440个表时出现了问题,而且我发现,在Table5440表中丢了500行数(原应该为5439001~5440000,现在是5439501~5440500),也就是说,有一次批量存储没有存进去。

16 个解决方案

#1


你的脚本中的表名TableName是怎么生成的?和数据行的index有关么?

#2


存在不就说明已经有表名称了,也许是有些错误导致序号计算重复。调试你的程序吧

#3


试一下定位到你的库

select * from 库名.INFORMATION_SCHEMA.TABLES where TABLE_NAME =表名

select * from 库名.sys.objects  where type='u' and name=表名

记住一点要加库名, 加或者不加可能是两个结果

#4


这个可能是一个并发问题。

#5


表名根据id定义,会做判断,满1000行创建一个新表

#6


1000行就存一个表,你是来折磨数据库的吗?
你起码放个几万几十万条记录,那才是合理使用。

#7


你给的信息也太少,而且还是偶发,很难判定问题。加日志记录详细错误看看。

#8


程序的提示和sql日志就是这四张图片

#9


使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?
使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?
使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?
使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?

#10


连接所使用代码如下(由于代码无法复制黏贴,我就给出关键的思路哈,希望大家不要介意):
using(SqlConnection con=new SqlConnection("server=(local);integrated security =SSPI;database=Database2"))
{
con.open();
创建表并将数据存入表中
con.close();
con.dispose();
}
其中,创建创建表之前会先用"if not exists"判断,若不存在,则创建;判断如下:
if not exists(select * from Database2.dbo.sysobjects where objectproperty(object_id('Table2'),'istable')=1)create......

#11


貌似多线程同时跑建表的代码带来的并发冲突。

#12


好像是,加快了发送速度,这个异常就出现的快些,我再测试下

#13


引用 12 楼 youarenotme 的回复:
好像是,加快了发送速度,这个异常就出现的快些,我再测试下

我上面已经说了。这个可能是一个并发问题。
你在创建表的时候 Lock一下

#14


看日志,只这么点数据看不出什么
1000行建立一个表,一般不会这么设计,1k万数据,要建立1万个表吗?无论是管理,还是操作,都很不方便的

你的问题,是忽略了ExecuteNonQuery()的返回值,你的command(if not exists(select * from ....),执行成功返回-1,否则,会throw  a Exception

try
{
    if(ExecuteNonQuery()==-1)
    {
        do something;
    }
}
catch
{
    //启动容错机制:建表失败
}



#15


其实只要使用数据库的分区功能(一个表按分区标识,在几个表文件中存储)就可以了,没必要人为的分表

#16


至于为什么会出现建表失败,这个跟你程序(C#)是不是多线程、如何操作从库里读出的数据等等无关,要知道,你用C#操作数据库,只是将特定T-SQL语句提交给数据库服务器,然后由DBMS(等效于数据库的操作系统)安排你的语句(T-SQL)执行的,sql数据源是支持并发的,也就是来自不同程序的request,DBMS都要排队、并发安排,等待执行你的提交,并将结果返回给程序。

#1


你的脚本中的表名TableName是怎么生成的?和数据行的index有关么?

#2


存在不就说明已经有表名称了,也许是有些错误导致序号计算重复。调试你的程序吧

#3


试一下定位到你的库

select * from 库名.INFORMATION_SCHEMA.TABLES where TABLE_NAME =表名

select * from 库名.sys.objects  where type='u' and name=表名

记住一点要加库名, 加或者不加可能是两个结果

#4


这个可能是一个并发问题。

#5


表名根据id定义,会做判断,满1000行创建一个新表

#6


1000行就存一个表,你是来折磨数据库的吗?
你起码放个几万几十万条记录,那才是合理使用。

#7


你给的信息也太少,而且还是偶发,很难判定问题。加日志记录详细错误看看。

#8


程序的提示和sql日志就是这四张图片

#9


使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?
使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?
使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?
使用了If not exists先判断数据库中的表是否存在,为什么还会报错“数据库中已存在名为‘Table345’的对象”?

#10


连接所使用代码如下(由于代码无法复制黏贴,我就给出关键的思路哈,希望大家不要介意):
using(SqlConnection con=new SqlConnection("server=(local);integrated security =SSPI;database=Database2"))
{
con.open();
创建表并将数据存入表中
con.close();
con.dispose();
}
其中,创建创建表之前会先用"if not exists"判断,若不存在,则创建;判断如下:
if not exists(select * from Database2.dbo.sysobjects where objectproperty(object_id('Table2'),'istable')=1)create......

#11


貌似多线程同时跑建表的代码带来的并发冲突。

#12


好像是,加快了发送速度,这个异常就出现的快些,我再测试下

#13


引用 12 楼 youarenotme 的回复:
好像是,加快了发送速度,这个异常就出现的快些,我再测试下

我上面已经说了。这个可能是一个并发问题。
你在创建表的时候 Lock一下

#14


看日志,只这么点数据看不出什么
1000行建立一个表,一般不会这么设计,1k万数据,要建立1万个表吗?无论是管理,还是操作,都很不方便的

你的问题,是忽略了ExecuteNonQuery()的返回值,你的command(if not exists(select * from ....),执行成功返回-1,否则,会throw  a Exception

try
{
    if(ExecuteNonQuery()==-1)
    {
        do something;
    }
}
catch
{
    //启动容错机制:建表失败
}



#15


其实只要使用数据库的分区功能(一个表按分区标识,在几个表文件中存储)就可以了,没必要人为的分表

#16


至于为什么会出现建表失败,这个跟你程序(C#)是不是多线程、如何操作从库里读出的数据等等无关,要知道,你用C#操作数据库,只是将特定T-SQL语句提交给数据库服务器,然后由DBMS(等效于数据库的操作系统)安排你的语句(T-SQL)执行的,sql数据源是支持并发的,也就是来自不同程序的request,DBMS都要排队、并发安排,等待执行你的提交,并将结果返回给程序。