创建最初禁用的唯一约束
Create unique constraint initially disabled
这是我的 table :
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
我的想法是 enable/disable 一种或其他独特的约束,具体取决于客户应用程序。通过这种方式,我可以在我的 C# 代码中捕获抛出的异常,并向 GUI 显示特定的错误消息。
现在,我的问题是更改列 Name1
和 Name2
的排序规则,我需要让它们区分大小写 (French_CS_AS
)。要更改这些字段,我必须删除这两个约束并重新创建它。根据解释的架构,我无法创建一个已启用的约束然后将其禁用,因为某些客户认为我有一个或其他约束的重复键。
对于我的更新脚本,我的第一个想法是
- 在临时文件中保存已启用约束的名称table
- 放弃约束
- 改变列
- 创建DISABLED 唯一约束
- 根据点 1 中保存的值启用特定约束。
我的问题在第 4 点,我找不到如何使用 ALTER TABLE
语句创建禁用的唯一约束。是否可以直接在 sys.indexes
table 中创建它?
我的第二个想法是
- 将 TestTable 重命名为 TestTableCopy
- 使用新的字段排序规则重新创建 TestTable,否则使用相同的架构(索引、FK、触发器...)
- 在 TestTable 中禁用特定的唯一约束
- 将数据从 TestTableCopy 迁移到 TestTable
- 删除 TestTableCopy
通过这种方式,我担心会失去与其他 tables/dependencies 的一些链接,因为它是我数据库中的中心 table。
还有其他方法可以实现我的目标吗?
如有必要,我可以使用唯一索引而不是唯一约束。
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。然后,如果你根据你的约束来做 insert/update。
看起来不可能在已经有重复值的列上创建唯一索引。
因此,与其禁用唯一索引,不如:
- 根本没有索引(从查询处理器的角度来看,这与禁用索引相同),
- 或者创建一个非唯一索引。
对于那些您的客户具有唯一数据的实例,创建唯一索引。对于那些您的客户具有非唯一数据的实例,创建非唯一索引。
这是我的 table :
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
我的想法是 enable/disable 一种或其他独特的约束,具体取决于客户应用程序。通过这种方式,我可以在我的 C# 代码中捕获抛出的异常,并向 GUI 显示特定的错误消息。
现在,我的问题是更改列 Name1
和 Name2
的排序规则,我需要让它们区分大小写 (French_CS_AS
)。要更改这些字段,我必须删除这两个约束并重新创建它。根据解释的架构,我无法创建一个已启用的约束然后将其禁用,因为某些客户认为我有一个或其他约束的重复键。
对于我的更新脚本,我的第一个想法是
- 在临时文件中保存已启用约束的名称table
- 放弃约束
- 改变列
- 创建DISABLED 唯一约束
- 根据点 1 中保存的值启用特定约束。
我的问题在第 4 点,我找不到如何使用 ALTER TABLE
语句创建禁用的唯一约束。是否可以直接在 sys.indexes
table 中创建它?
我的第二个想法是
- 将 TestTable 重命名为 TestTableCopy
- 使用新的字段排序规则重新创建 TestTable,否则使用相同的架构(索引、FK、触发器...)
- 在 TestTable 中禁用特定的唯一约束
- 将数据从 TestTableCopy 迁移到 TestTable
- 删除 TestTableCopy
通过这种方式,我担心会失去与其他 tables/dependencies 的一些链接,因为它是我数据库中的中心 table。
还有其他方法可以实现我的目标吗?
如有必要,我可以使用唯一索引而不是唯一约束。
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。然后,如果你根据你的约束来做 insert/update。
看起来不可能在已经有重复值的列上创建唯一索引。
因此,与其禁用唯一索引,不如:
- 根本没有索引(从查询处理器的角度来看,这与禁用索引相同),
- 或者创建一个非唯一索引。
对于那些您的客户具有唯一数据的实例,创建唯一索引。对于那些您的客户具有非唯一数据的实例,创建非唯一索引。