我有以下查询
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
吗?但我不能因为有一些变数
答案 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有相同的问题(即需要一个复合主键)。因此,假设我们希望在ContractID
和PersonID
的组合上使用主键。在这种情况下(假定您具有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,错误消息: 无法创建约束或索引。查看以前的错误。