简体   繁体   English

两个唯一列的非唯一组合

[英]non unique combination of two unique columns

I have table with columns code, id and date and some other date. 我有列代码,id日期和其他一些日期的表。 These columns are primary key together. 这些列一起是主键。

primary key(id, code, date)

I want them to be unique together. 我希望它们在一起是独一无二的。 But a code cannot be duplicated in table with two different ids. 但是代码不能在具有两个不同ID的表中重复。 For example this is a possible situation: 例如,这是一种可能的情况:

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

or even this 甚至这个

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

while this is not: 虽然不是:

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

it's possible to have two rows with code "123" only if id of both rows is 1. "123" cannot be combined with any other ids. 仅当两行的ID均为1时,才可能有两行代码为“ 123”。“ 123”不能与任何其他ID组合。

How can I manage this in sql server (version 14)? 如何在sql server(版本14)中管理此问题?

You have the wrong data model. 您的数据模型错误。

You need one table with only id and code (and whatever columns other than date might be relevant. Let's call this table codes and the id, code_id , because that is how I would name them: 您需要一个仅包含idcode表(以及除date之外的任何其他列都可能是相关的。让我们将此表codes和id code_id ,因为这就是我的命名方式:

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

There. 那里。 Now the mapping between code_id and code is one-to-one. 现在, code_idcode之间的映射是一对一的。 Next, create a table using only code_id and date : 接下来,仅使用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)
);

You can look up the code using code_id . 您可以使用code_id查找code Voila! 瞧! Your data model is fixed. 您的数据模型是固定的。

Gordon's answer is the best advice, but treating your question as academic, you can manage what you want using a CHECK CONSTRAINT in addition to the PRIMARY KEY you already have. Gordon的答案是最好的建议,但是将您的问题视为学术问题,除了您已有的PRIMARY KEY外,您还可以使用CHECK CONSTRAINT来管理所需的内容。

The CHECK CONSTRAINT would call a function that takes id and code as parameters. CHECK CONSTRAINT将调用一个以idcode为参数的函数。 The function queries the table and returns true if there is no other id that has that code , or false otherwise. 该函数查询表,如果没有其他具有该code id ,则返回true否则返回false The CONSTRAINT allows only rows where the function returns true . CONSTRAINT仅允许函数返回true行。

This might do it 这可能会做到

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;

Why don't you create a Lookup table whose primary key is id , code ? 为什么不创建主键为idcode的Lookup表? By putting a UNIQUE constraint on code , you will ensure that code = 123 will only every pair up with id = 1 . 通过对code施加UNIQUE约束,您将确保code = 123只会对id = 1每对配对。 We cannot put code = 123 against id = 2 without violating the constraint. 我们不能在不违反约束的情况下将code = 123id = 2放在一起。

Then put a referential constraint between the Lookup table and your Business table. 然后在查阅表和您的业务表之间放置一个引用约束。 Then, the referential constraint will bring over the constraints from the Lookup table into the Business table which will persist that code = 123 can only every match with id = 1 . 然后,引用约束将把约束从Lookup表转移到Business表,该表将坚持认为code = 123只能匹配id = 1每个匹配项。

Something like: 就像是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM