AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 43823
Accepted
Matthew
Matthew
Asked: 2013-06-05 09:41:59 +0800 CST2013-06-05 09:41:59 +0800 CST 2013-06-05 09:41:59 +0800 CST

我可以添加一个忽略现有违规的唯一约束吗?

  • 772

我有一个表,该表当前在一列中有重复的值。

我无法删除这些错误的重复项,但我想防止添加其他非唯一值。

我可以创建一个UNIQUE不检查现有合规性的文件吗?

我曾尝试使用NOCHECK但不成功。

在这种情况下,我有一个将许可信息与“CompanyName”联系起来的表

编辑:具有相同“公司名称”的多行是错误数据,但我们目前无法删除或更新这些重复项。一种方法是让INSERTs 使用一个存储过程,该过程会因重复而失败......如果可以让 SQL 自己检查唯一性,那将是可取的。

该数据按公司名称查询。对于少数现有的重复项,这将意味着返回并显示多行......虽然这是错误的,但在我们的用例中是可以接受的。目标是防止它在未来发生。在我看来,我必须在存储过程中执行此逻辑。

sql-server database-design
  • 5 5 个回答
  • 52936 Views

5 个回答

  • Voted
  1. Best Answer
    Gordon Linoff
    2013-06-05T10:28:38+08:002013-06-05T10:28:38+08:00

    答案是“是”。您可以使用过滤索引来执行此操作(有关文档,请参见此处)。

    例如,您可以这样做:

    create unique index t_col on t(col) where id > 1000;
    

    这将创建一个唯一索引,仅在新行上,而不是在旧行上。这种特定的公式将允许使用现有值进行重复。

    如果您只有少数重复项,则可以执行以下操作:

    create unique index t_col on t(col) where id not in (<list of ids for duplicate values here>);
    
    • 39
  2. A-K
    2013-06-05T13:06:03+08:002013-06-05T13:06:03+08:00

    是的,你可以这么做。

    这是一个重复的表:

    CREATE TABLE dbo.Party
      (
        ID INT NOT NULL
               IDENTITY ,
        CONSTRAINT PK_Party PRIMARY KEY ( ID ) ,
        Name VARCHAR(30) NOT NULL
      ) ;
    GO
    
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Frodo Baggins' ),
            ( 'Luke Skywalker' ),
            ( 'Luke Skywalker' ),
            ( 'Harry Potter' ) ;
    GO
    

    让我们忽略现有的,并确保不能添加新的重复项:

    -- Add a new column to mark grandfathered duplicates.
    ALTER TABLE dbo.Party ADD IgnoreThisDuplicate INT NULL ;
    GO
    
    -- The *first* instance will be left NULL.
    -- *Secondary* instances will be set to their ID (a unique value).
    UPDATE  dbo.Party
    SET     IgnoreThisDuplicate = ID
    FROM    dbo.Party AS my
    WHERE   EXISTS ( SELECT *
                     FROM   dbo.Party AS other
                     WHERE  other.Name = my.Name
                            AND other.ID < my.ID ) ;
    GO
    
    -- This constraint is not strictly necessary.
    -- It prevents granting further exemptions beyond the ones we made above.
    ALTER TABLE dbo.Party WITH NOCHECK
    ADD CONSTRAINT CHK_Party_NoNewExemptions 
    CHECK(IgnoreThisDuplicate IS NULL);
    GO
    
    SELECT * FROM dbo.Party;
    GO
    
    -- **THIS** is our pseudo-unique constraint.
    -- It works because the grandfathered duplicates have a unique value (== their ID).
    -- Non-grandfathered records just have NULL, which is not unique.
    CREATE UNIQUE INDEX UNQ_Party_UniqueNewNames ON dbo.Party(Name, IgnoreThisDuplicate);
    GO
    

    让我们测试一下这个解决方案:

    -- cannot add a name that exists
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Frodo Baggins' );
    
    Cannot insert duplicate key row in object 'dbo.Party' with unique index 'UNQ_Party_UniqueNewNames'.
    
    -- cannot add a name that exists and has an ignored duplicate
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Luke Skywalker' );
    
    Cannot insert duplicate key row in object 'dbo.Party' with unique index 'UNQ_Party_UniqueNewNames'.
    
    
    -- can add a new name 
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Hamlet' );
    
    -- but only once
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Hamlet' );
    
    Cannot insert duplicate key row in object 'dbo.Party' with unique index 'UNQ_Party_UniqueNewNames'.
    
    • 25
  3. ypercubeᵀᴹ
    2013-06-05T13:00:38+08:002013-06-05T13:00:38+08:00

    过滤的唯一索引是一个绝妙的主意,但它有一个小缺点 - 无论您使用WHERE identity_column > <current value>条件还是WHERE identity_column NOT IN (<list of ids for duplicate values here>).

    使用第一种方法,您将来仍然可以插入重复数据,即现有(现在)数据的重复。例如,如果您现在有(甚至只有一行)带有的行CompanyName = 'Software Inc.',则索引不会禁止再插入一行具有相同公司名称的行。如果您尝试两次,它只会禁止它。

    使用第二种方法有一个改进,上述方法不起作用(这很好)。但是,您仍然可以插入更多重复项或现有重复项。例如,如果您现在有(两行或多行)带有的行CompanyName = 'DoubleData Co.',则索引不会禁止再插入一行具有相同公司名称的行。如果您尝试两次,它只会禁止它。

    (更新)如果对于每个重复的名称,您可以在排除列表之外保留一个 id,则可以更正此问题。如果像上面的示例一样,有 4 行具有重复的CompanyName = DoubleData Co.ID 和 ID 4,6,8,9,则排除列表应该只有 3 个这些 ID。

    第二种方法的另一个缺点是繁琐的条件(繁琐的程度首先取决于有多少重复项),因为 SQL-Server 似乎不支持过滤索引部分的NOT IN运算符。WHERE请参阅SQL-Fiddle。WHERE (CompanyID NOT IN (3,7,4,6,8,9))如果您有数百个重复名称,那么您将不得不有类似WHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)I'm not sure if there is anefficiency with this condition,而不是。


    另一种解决方案(类似于@Alex Kuznetsov 的)是添加另一列,用排名数字填充它并添加一个包含此列的唯一索引:

    ALTER TABLE Company
      ADD Rn TINYINT DEFAULT 1;
    
    UPDATE x
    SET Rn = Rnk
    FROM
      ( SELECT 
          CompanyID,
          Rn,
          Rnk = ROW_NUMBER() OVER (PARTITION BY CompanyName 
                                   ORDER BY CompanyID)
        FROM Company 
      ) x ;
    
    CREATE UNIQUE INDEX CompanyName_UQ 
      ON Company (CompanyName, Rn) ; 
    

    DEFAULT 1然后,由于属性和唯一索引,插入具有重复名称的行将失败。这仍然不是 100% 万无一失(而亚历克斯是)。Rn如果在语句中明确设置INSERT或Rn值被恶意更新 ,重复项仍然会溜进来。

    SQL-Fiddle-2

    • 17
  4. Greenstone Walker
    2013-06-05T17:45:02+08:002013-06-05T17:45:02+08:00

    另一种选择是编写一个标量函数来检查表中是否已经存在值,然后从检查约束中调用该函数。

    这将对性能造成可怕的影响。

    • -2
  5. Brad
    2015-10-30T11:08:06+08:002015-10-30T11:08:06+08:00

    我正在寻找相同的东西 - 创建一个不受信任的唯一索引,以便忽略现有的错误数据,但新记录不能与已经存在的任何内容重复。

    在阅读此线程时,我想到一个更好的解决方案是编写一个触发器,该触发器将针对父表检查 [inserted] 是否存在重复项,如果这些表之间存在任何重复项,则 ROLLBACK TRAN。

    • -2

相关问题

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 在数据仓库中实现多对多关系有哪些方法?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    授予用户对所有表的访问权限

    • 5 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve