【问题标题】:Create unique constraint initially disabled创建唯一约束最初禁用
【发布时间】:2015-10-01 08:18:05
【问题描述】:

这是我的桌子:

CREATE TABLE [dbo].[TestTable] 
(
  [Name1] varchar(50) COLLATE French_CI_AS NOT NULL,
  [Name2] varchar(255) COLLATE French_CI_AS NULL,
  CONSTRAINT [TestTable_uniqueName1] UNIQUE ([Name1]),
  CONSTRAINT [TestTable_uniqueName1Name2] UNIQUE ([Name1], [Name2])
)

ALTER TABLE [dbo].[TestTable]
ADD CONSTRAINT [TestTable_uniqueName1] 
UNIQUE NONCLUSTERED ([Name1])

ALTER TABLE [dbo].[TestTable]
ADD CONSTRAINT [TestTable_uniqueName1Name2] 
UNIQUE NONCLUSTERED ([Name1], [Name2])
GO

ALTER INDEX [TestTable_uniqueName1]
  ON [dbo].[TestTable]
  DISABLE
GO

我的想法是根据客户应用程序启用/禁用一个或其他独特的约束。通过这种方式,我可以在我的 c# 代码中捕获抛出的异常,并向 GUI 显示特定的错误消息。

现在,我的问题是更改列 Name1Name2 的排序规则,我需要使它们区分大小写 (French_CS_AS)。要更改这些字段,我必须删除这两个约束并重新创建它。根据解释的架构,我无法创建启用的约束然后禁用它,因为对于某些客户,我有一个或其他约束的重复键。

对于我的更新脚本,我的想法 1 是

  1. 将已启用约束的名称保存在临时表中
  2. 放弃约束
  3. 更改列
  4. 创建DISABLED唯一约束
  5. 根据点 1 中保存的值启用特定约束。

我的问题在第 4 点,我找不到如何使用 ALTER TABLE 语句创建禁用的唯一约束。是否可以直接在sys.indexes表中创建?

我的想法 2 是

  1. 将 TestTable 重命名为 TestTableCopy
  2. 使用新字段排序规则重新创建 TestTable,否则使用相同的架构(索引、FK、触发器...)
  3. 在 TestTable 中禁用特定的唯一约束
  4. 将数据从 TestTableCopy 迁移到 TestTable
  5. 删除 TestTableCopy

这样,我担心会失去与其他表/依赖项的一些链接,因为它是我数据库中的中心表。

还有其他方法可以实现我的目标吗?

如有必要,我可以使用唯一索引而不是唯一约束。

【问题讨论】:

  • 为什么不能忘记 Unique 约束,在向表中添加记录时检查自己并捕获异常?
  • 因为可以通过多种方式插入记录(使用 t-sql,从我的 c# 应用程序,...)。我希望数据库检查我的数据。
  • 创建一个存储过程来将记录插入到表中,您可以将它用于您需要的所有类型的插入。在存储过程中根据您的需要检查约束。我会这样做。更改表格不是一个好习惯。
  • 所以我需要另一个存储过程来编辑我的行...这种方式我不喜欢 100%。为什么更改表不是最佳实践?无论哪种方式,我都需要一个更改表来更改我的 varchar 列的长度...
  • 看看我的例子。

标签: tsql sql-server-2008-r2 unique-constraint unique-index


【解决方案1】:

看起来不可能在已经有重复值的列上创建唯一索引。

因此,与其禁用唯一索引:

  • 根本没有索引(从查询处理器的角度来看,这与禁用索引相同),
  • 或创建非唯一索引。

对于那些您的客户拥有唯一数据的实例,请创建唯一索引。对于那些您的客户具有非唯一数据的实例,请创建非唯一索引。

【讨论】:

  • 你是对的!我在很多方面进行了搜索,不可能创建禁用的唯一约束或禁用的唯一索引。我的解决方案是放弃我的约束,更改我的列,并仅重新创建最初启用的那些。
【解决方案2】:
CREATE PROCEDURE [dbo].[spUsers_AddUsers]
@Name1 varchar(50)  ,
@Name2 varchar(50) ,
@Unique bit 
AS

declare @err int
begin tran
    if @Unique = 1 begin
 if not exists (SELECT * FROM Users WHERE Name1 = @Name1 and Name2 = @Name2) 
 begin
     INSERT INTO Users (Name1,Name2) 
   VALUES (@Name1,@Name2)
   set @err = @@ERROR
 end else
 begin
   UPDATE Users
   set Name1 = @Name1,
   Name2 = @Name2
   where Name1 = @Name1 and Name2 = @Name2
   set @err = @@ERROR
 end   

end else begin
    if not exists ( SELECT * FROM Users WHERE Name1 = @Name1 )
    begin
         INSERT INTO Users (Name1,Name2) 
         VALUES (@Name1,@Name2)
        set @err = @@ERROR
    end else
    begin
    UPDATE Users
     set Name1 = @Name1,
         Name2 = @Name2
     where Name1 = @Name1 
     set @err = @@ERROR
end


 if @err = 0 commit tran
    else rollback tran

所以首先你检查你是否需要一个唯一的 Name1 和 Name2 或者只是 Name1。然后,如果您根据您拥有的约束进行插入/更新。

【讨论】:

  • 我理解你的做法,但只有在我不能换桌子的情况下才会考虑。我所有的数据库都是用约束设计的,我认为这不是一个坏方法。
  • 不是,我一直都在用约束,在每个db中都是很重要的一部分,但是你的情况好像有点诡异,我从来没有遇到过(每次都要改约束)。
猜你喜欢
  • 1970-01-01
  • 2016-06-04
  • 1970-01-01
  • 1970-01-01
  • 2019-02-24
  • 2015-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多