mar*_*are 4 sql-server unique-constraint
我发现自己所处的情况是由于某种原因我将错误的数据输入到数据库中。我想通过UNIQUE INDEX在UFID字段上添加到用户表 a 来保持数据完整性。
自然地,我生成了一个脚本,以非破坏性的方式删除任何重复的记录:
update [user]
set UFID = UFID + '_dup_removal'
where ufid in (
select ufid
from [user]
group by ufid
having count(ufid) > 1
)
Run Code Online (Sandbox Code Playgroud)
然后我发现该字段无法在UNIQUE INDEX.
那么现在获得结果的最佳方法是什么,我有用户表和数据并添加了UNIQUE INDEX.
注意:它应该以允许轻松逆转的方式完成。
正如您所发现的,varchar(max) 列不能被索引。您将需要索引其他内容。
它可以是数据的缩短版本(只有您可以判断这是否可以接受)或数据的散列版本。哈希冲突的几率非常低。
USE tempdb;
IF OBJECT_ID('user') IS NOT NULL
DROP TABLE [user];
CREATE TABLE [user] (
UFID varchar(max)
)
INSERT INTO [user] VALUES(1),(2),(3),(4),(4),(4),(3),(5);
WITH ranked_users AS (
SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY UFID ORDER BY (SELECT NULL))
FROM [user]
)
update ranked_users
set UFID = UFID + '_dup_removal_' + CAST(RN AS varchar(10))
where RN > 1;
--CREATE UNIQUE INDEX IX_UFID ON [user](UFID) -- FAILS
-- Solution 1: add a computed column with the size trimmed down
ALTER TABLE [user] ADD shortened_ufid AS CAST(UFID AS varchar(900))
CREATE UNIQUE INDEX IX_shortened_UFID ON [user](shortened_ufid)
-- Solution 2: add a computed column with the hashed version of the data
ALTER TABLE [user] ADD hashed_ufid AS CAST(HASHBYTES('SHA1', UFID) AS bigint)
CREATE UNIQUE INDEX IX_hashed_UFID ON [user](hashed_UFID)
SELECT *
FROM [user]
GO
Run Code Online (Sandbox Code Playgroud)
另一种选择是清理数据,然后确保不会使用触发器插入重复项。不过,这将是非常缓慢的。
-- solution 3: use a trigger
CREATE TRIGGER TR_no_dupes ON [user]
FOR INSERT, UPDATE
AS
BEGIN
IF EXISTS (
SELECT 1
FROM [user]
WHERE UFID IN (
SELECT UFID
FROM inserted
)
GROUP BY UFID
HAVING COUNT(*) > 1
)
ROLLBACK;
END
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8780 次 |
| 最近记录: |