【问题标题】:Update duplicate varchars to be unique in SQL database更新重复的 varchars 在 SQL 数据库中是唯一的
【发布时间】:2010-10-22 05:33:39
【问题描述】:

我需要更改一个数据库以在表列上添加唯一约束,但其中的 VARCHAR 数据不是唯一的。

如何通过在现有数据的末尾添加序列号来更新这些重复记录,以便每个值都是唯一的?

例如我想将 'name' 更改为 'name1'、'name2'、'name3'

【问题讨论】:

    标签: sql database unique duplicates


    【解决方案1】:

    这里有 2 个使用 MS SQL SERVER 风格的 sql 的示例。

    设置示例:

    create table test (id int identity primary key, val varchar(20) )
        --id is a pk for the cursor so it can update using "where current of"
    
    -- name a is not duplicated
    -- name b is duplicated 3 times
    -- name c is duplicated 2 times
    
    insert test values('name a')
    insert test values('name b')
    insert test values('name c')
    insert test values('name b')
    insert test values('name b')
    insert test values('name c')
    

    Sql 2005\2008:(计算表表达式)

    begin tran; -- Computed table expressions require the statement prior to end with ;
    
    with cte(val,row) as (
    
        select val, row_number() over (partition by val order by val) row
        --partiton is important. it resets the row_number on a new val
        from test 
        where val in ( -- only return values that are duplicated
            select val
            from test
            group by val
            having count(val)>1
        )
    )
    update cte set val = val + ltrim(str(row))
    --ltrim(str(row)) = converting the int to a string and removing the padding from the str command.
    
    select * from test
    
    rollback
    

    Sql 2000:(光标示例)

    begin tran
    
    declare @row int, @last varchar(20), @current varchar(20)
    set @last = ''
    declare dupes cursor
        for
        select val 
        from test 
        where val in ( -- only return values that are duplicated
            select val
            from test
            group by val
            having count(val)>1
        )
        order by val
    
        for update of val
    
    open dupes
    fetch next from dupes into @current
    while @@fetch_status = 0
    begin
        --new set of dupes, like the partition by in the 2005 example
        if @last != @current
            set @row = 1
    
        update test
            --@last is being set during the update statement
            set val = val + ltrim(str(@row)), @last = val
            where current of dupes
    
        set @row = @row + 1
    
        fetch next from dupes into @current
    end
    close dupes
    deallocate dupes
    
    select * from test
    
    rollback
    

    我回滚了每个更新,因为我的脚本文件包含这两个示例。这使我可以在不重置表格行的情况下测试功能。

    【讨论】:

      【解决方案2】:

      在表格上打开一个光标,按该列排序。保留前一个值变量,初始化为 null,索引变量初始化为 0。如果当前值 = 前一个值,则递增索引并将索引附加到字段值。如果当前值 前一个值,则将索引重置为 0 并保持字段值不变。设置前一个值变量 = 当前值。移动到下一行并重复。

      【讨论】:

        【解决方案3】:

        您可以在其中添加另一列...例如

        update mytable set mycolumn = concat(mycolumn, id) 
                    where id in (<select duplicate records>);
        

        将 id 替换为使 mycolumn 唯一的任何列

        【讨论】:

          【解决方案4】:

          你用的是什么数据库?

          Oracle 中有一个:

          NOVALIDATE 验证更改,但不验证表中先前存在的数据

          例子:

          ALTER TABLE <table_name> ENABLE NOVALIDATE UNIQUE;
          

          如果您不使用 Oracle,请检查您各自数据库的 SQL 参考。

          【讨论】:

          • 我们正在使用 FrontBase(符合 SQL92)我希望验证和更新现有数据
          • 我知道这不是他要求的,但我确实在他告诉我他正在使用 FrontBase 之前写了它,我什至不知道。然而,原理是一样的:数据库可以有一些类似于 NOVALIDATE 子句的东西。如果您认为 CONSTRAINT 的类型会发生任何变化,请不要介意 PRIMARY KEY。
          • 问题是如何更新将失败所需的新约束的数据。你的答案是让数据库忽略失败。虽然很有趣,但这听起来不是一个好主意。
          猜你喜欢
          • 2019-03-08
          • 2020-12-06
          • 2022-12-06
          • 1970-01-01
          • 2019-09-05
          • 1970-01-01
          • 2023-02-16
          • 2019-02-10
          • 1970-01-01
          相关资源
          最近更新 更多