【问题标题】:non unique combination of two unique columns两个唯一列的非唯一组合
【发布时间】:2018-03-28 06:09:27
【问题描述】:

我的表格包含 code、iddate 列以及其他一些日期。 这些列一起是主键。

primary key(id, code, date)

我希望它们在一起是独一无二的。但是一个代码不能在具有两个不同 id 的表中重复。 例如这是一种可能的情况:

id   code  date        data
1    123   3/28/2018   "data 1"
1    123   4/28/2018   "data 2"

甚至这个

1    123   3/28/2018   "data 1"
1    124   3/28/2018   "data 2"

虽然不是这样:

id   code  date        data
1    123   3/28/2018   "data 1"
2    123   4/28/2018   "data 2"

只有当两行的 id 都为 1 时,才有可能有两行代码为“123”。“123”不能与任何其他 id 组合。

如何在 sql server(版本 14)中管理这个?

【问题讨论】:

  • 请编辑您的问题,并提供清楚的例子说明什么是允许的,什么是不允许的。
  • 相反的可能吗?相同的id 有两个不同的code 值?
  • 是的,这是可能的。 @SunKnight0

标签: sql sql-server database


【解决方案1】:

你有错误的数据模型。

您需要一张只有idcode 的表(以及除date 之外的任何其他列可能相关。让我们将此表称为codes 和ID code_id,因为这就是我想要的给他们起名字:

create table codes (
    code_id int identity(1, 1) primary key,
    code varchar(255) not null unique
);

那里。现在code_idcode 之间的映射是一对一的。接下来,只使用code_iddate 创建一个表:

create table code_dates (
    code_date_id int identity(1, 1) primary key,
    code_id int,
    date date,
    contraint fk_code_dates_code_id foreign key (code_id) references codes(code_id)
);

您可以使用code_id 查找code。瞧!你的数据模型是固定的。

【讨论】:

  • 感谢您的回答。但是有没有办法在不改变数据模型的情况下做到这一点?
  • @madreza 如果您无法更改数据模型,您希望如何解决这个问题?
  • 我可能会改变模型,但我想知道是否有办法做到这一点。我认为 Tab Alleman 的建议会奏效。 @paparazzo
【解决方案2】:

Gordon 的回答是最好的建议,但是将您的问题视为学术问题,除了您已有的 PRIMARY KEY 之外,您还可以使用 CHECK CONSTRAINT 来管理您想要的内容。

CHECK CONSTRAINT 将调用一个以idcode 作为参数的函数。如果没有其他id 具有code,则该函数查询表并返回true,否则返回false。 CONSTRAINT 只允许函数返回 true 的行。

【讨论】:

    【解决方案3】:

    这可能会成功

    create table tmp (id int not null,  code int not null, dt datetime not null,  data varchar(10)
                       primary key (id, code, dt));
    create function dbo.CheckFunction(@id int, @code int)
    returns int
    as begin
        return (select count(*) from tmp t where t.id <> @id and t.code = @code) 
    end;
    alter table tmp
    add constraint chk_CheckFunction
    check (dbo.CheckFunction(id, code) = 0);
    
    truncate table tmp;
    insert into tmp values 
           (1 ,123, '3/28/2018', 'data 1')
         , (1 ,123, '4/28/2018', 'data 2')
         , (1 ,123, '5/28/2018', 'data 2');
    select * from tmp;
    select count(*) from tmp t where t.id <> 1 and t.code = 123;
    insert into tmp values 
           (2 ,123, '3/28/2018', 'data 1');
    select * from tmp;
    
    drop table tmp;
    drop function dbo.CheckFunction;
    

    【讨论】:

      【解决方案4】:

      为什么不创建一个主键为idcode 的查找表?通过在code 上设置UNIQUE 约束,您将确保code = 123 只会与id = 1 配对。我们不能在不违反约束的情况下将code = 123id = 2 放在一起。

      然后在 Lookup 表和您的 Business 表之间放置一个引用约束。然后,引用约束会将 Lookup 表中的约束带到 Business 表中,该表将坚持 code = 123 只能与 id = 1 每次匹配。

      类似:

      DROP TABLE Business;
      DROP TABLE Lookup;
      
      CREATE TABLE Lookup
      (
          id INT NOT NULL,
          code INT NOT NULL UNIQUE,
          CONSTRAINT PK_Lookup Primary Key (id, code)
      );
      
      INSERT INTO Lookup VALUES (1, 123);
      INSERT INTO Lookup VALUES (1, 124);
      INSERT INTO Lookup VALUES (2, 123); -- Rejected
      
      CREATE TABLE Business
      (
        id int NOT NULL,
        code int NOT NULL,
        date date NOT NULL,
        data NVARCHAR(20) NOT NULL,
        CONSTRAINT PK_Business PRIMARY KEY (id, code, date),
        CONSTRAINT FK_Lookup FOREIGN KEY (id, code) REFERENCES Lookup (id, code)
      );
      
      INSERT INTO Business VALUES (1, 123, '2018-03-28', 'data 1');
      INSERT INTO Business VALUES (1, 123, '2018-04-28', 'data 2');
      INSERT INTO Business VALUES (1, 124, '2018-03-28', 'data 2');
      INSERT INTO Business VALUES (2, 123, '2018-04-28', 'data 2'); -- Rejected
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-17
        • 1970-01-01
        • 1970-01-01
        • 2022-12-14
        • 1970-01-01
        • 2019-04-03
        • 1970-01-01
        相关资源
        最近更新 更多