临时表的主键已存在

时间:2016-04-18 14:50:07

标签: sql-server tsql

我有以下查询

declare @var1 int, @var2 int
set @var1 = 110
set @var2 = 300

IF object_id('tempdb..#tbl_Contract') IS NOT NULL
BEGIN
   ALTER TABLE #tbl_Contract drop constraint PK_#tbl_Contract
   DROP TABLE #tbl_Contract
END

CREATE TABLE #tbl_Contract
(  ContractID int NOT NULL
,  PersonID int NOT NULL
,  EndDate smalldatetime NULL
,  CONSTRAINT [PK_#tbl_Contract] PRIMARY KEY CLUSTERED 
   (
     ContractID ASC
   )
)
...

但是当我第二次运行此查询时出现错误:

  

Msg 2714,Level 16,State 5,Line 1已经有一个名为的对象   数据库中的'PK_#tbl_Contract'。 Msg 1750,Level 16,State 0,   第1行无法创建约束。查看以前的错误。

我做错了什么?为什么我的主键没有删除?

我应该在GO之后使用ALTER吗?但我不能因为有一些变数

3 个答案:

答案 0 :(得分:3)

您不需要删除约束,然后立即删除该表。放下桌子更简单。此外,实际上不需要在临时表中命名约束。您可以像这样大大简化代码。

IF object_id('tempdb..#tbl_Contract') IS NOT NULL
BEGIN
   DROP TABLE #tbl_Contract
END

GO

CREATE TABLE #tbl_Contract
(  ContractID int NOT NULL PRIMARY KEY CLUSTERED
,  PersonID int NOT NULL
,  EndDate smalldatetime NULL
)

答案 1 :(得分:1)

我和注释中提到的@NReilingh有相同的问题(即需要一个复合主键)。因此,假设我们希望在ContractIDPersonID的组合上使用主键。在这种情况下(假定您具有EXEC的适当权限),可以进行以下操作:

IF object_id('tempdb..#tbl_Contract') IS NOT NULL
   DROP TABLE #tbl_Contract
GO
DECLARE @Q as nvarchar(MAX) = N'
CREATE TABLE #tbl_Contract (
   ContractID int NOT NULL
 , PersonID int NOT NULL
 , EndDate smalldatetime NULL
 , CONSTRAINT
     [PK_#tbl_Contract' + CAST(@@SPID as nvarchar(6)) + N']
   PRIMARY KEY CLUSTERED ( 
     ContractID ASC,
     PersonID ASC
   )
)'
EXEC (@Q)

之所以可行,是因为给定服务器上任何时候的每个连接都应具有唯一的SPID值。 SPID值通常是大于50的两位数;但类型为smallint,因此最长可能为5位数字,并且可能会被签名。

请记住在表格的DDL中将所有单引号加倍(即将'替换为''

答案 2 :(得分:0)

对于临时表上的复合主键约束,最好不要命名主键约束,否则您将在并发会话中遇到麻烦。通过以下方式,您还可以添加任意数量的索引或检查约束而无需命名它们:

IF object_id('tempdb..#tbl_Contract') IS NOT NULL
BEGIN
DROP TABLE #tbl_Contract
END

GO

CREATE TABLE #tbl_Contract
(  ContractID int NOT NULL
,  PersonID int NOT NULL
,  EndDate smalldatetime NULL
,  PRIMARY KEY CLUSTERED (ContractID ASC, PersonID ASC)
,  CHECK (ContractID > 10 AND EndDate > N'2019-12-31') 
)

这可以避免@mpag解决方案的陷阱,因为您可以在存储过程中进一步使用temp表。在@mpag的解决方案中,您不能在@Q语句之外使用#tbl_Contract。

即使在临时表上,也无法在不同的会话中创建具有相同名称的主键。如果您未命名主键和其他约束,则系统将为每个会话自动为它们指定一个不同的唯一名称。

否则,在不同会话中同时运行该过程时,将出现以下错误:

  

错误号:1750,错误过程:   dbo.ProcedureName,错误行:XXX,错误消息:   无法创建约束或索引。查看以前的错误。