我有一组父子表(1对多关系)。我正在构建表格,并对使用PK和自动增量有一些疑问。
父表具有自动编号PK(用于存储销售单标题)。这里的一条记录意味着票。
子表用于存储票证详细信息。这里的一个记录是票证中的一个行项目(例如可乐,火星酒吧等)
我知道子表的PK应该有2个字段:
如果我使用IDENTITY
,则在父亲的PK更改后不会“重启”。
我将用一个例子来展示它:
A)SQL做什么
Parent table
Col1 Col2
1 1000
2 2543
3 3454
Note: Col1 is IDENTITY
Child Table
Col1 Col2 Col3
1 1 Coke
1 2 Mars Bar
2 3 Sprite
3 4 Coke
3 5 Sprite
3 6 Mars Bar
Note: Col1 is taken from Parent Table; Col2 is IDENTITY
B)我想要实现的目标
Parent table is the same as above
Child Table
Col1 Col2 Col3
1 1 Coke
1 2 Mars Bar
2 1 Sprite
3 1 Coke
3 2 Sprite
3 3 Mars Bar
注意:Col1取自父表; Col2更改后Col2重置;由Col2组成的Col1是唯一的。
SQL Server是否实现了密钥的使用?或者我应该编码吗?
答案 0 :(得分:3)
仅作为一个例子:
create table dbo.tOrders (
OrderID int not null identity primary key,
CustomerID int not null
);
create table dbo.tOrderPos (
OrderID int not null foreign key references dbo.tOrders,
OrderPosNo int null,
ProductID int null
);
create clustered index ciOrderPos on dbo.tOrderPos
(OrderID, OrderPosNo);
go
create trigger dbo.trInsertOrderPos on dbo.tOrderPos for insert
as begin
update opo
set OrderPosNo = isnull(opo2.MaxOrderPosNo,0) + opo.RowNo
from (select OrderID, OrderPosNo,
RowNo = row_number() over (partition by OrderID order by (select 1))
from dbo.tOrderPos opo
where OrderPosNo is null) opo
cross apply
(select MaxOrderPosNo = max(opo2.OrderPosNo)
from dbo.tOrderPos opo2
where opo2.OrderID = opo.OrderID) opo2
where exists (select * from inserted i where i.OrderID = opo.OrderID);
end;
go
declare @OrderID1 int;
declare @OrderID2 int;
insert into dbo.tOrders (CustomerID) values (11);
set @OrderID1 = scope_identity();
insert into dbo.tOrderPos (OrderID, ProductID)
values (@OrderID1, 1), (@OrderID1, 2), (@OrderID1, 3);
insert into dbo.tOrders (CustomerID) values (12);
set @OrderID2 = scope_identity();
insert into dbo.tOrderPos (OrderID, ProductID)
values (@OrderID2, 4), (@OrderID2, 5);
insert into dbo.tOrderPos (OrderID, ProductID)
values (@OrderID1, 6);
select * from dbo.tOrderPos;
go
drop trigger dbo.trInsertOrderPos;
drop table dbo.tOrderPos;
drop table dbo.tOrders;
go
困难在于允许多个插入和延迟插入。 HTH
另一种选择是使用替代触发器:
create trigger dbo.trInsertOrderPos on dbo.tOrderPos instead of insert
as begin
insert into dbo.tOrderPos
(OrderID, OrderPosNo, ProductID)
select OrderID,
OrderPosNo =
isnull( (select max(opo.OrderPosNo)
from dbo.tOrderPos opo
where opo.OrderID = i.OrderID), 0) +
row_number() over (partition by OrderID order by (select 1)),
ProductID
from inserted i;
end;
不幸的是,似乎无法将OrderPosNo设置为“not null”,因为多次插入会导致重复键。因此,我无法使用主键并改为使用聚簇索引。
答案 1 :(得分:1)
你没有一对多的关系。 你有多对多的关系。 父母可以有很多项目。 可乐可以属于多个父母。
你想要三张桌子。中间表有时称为联结表。
http://en.wikipedia.org/wiki/Junction_table
注意:在wiki文章中,他们只在联结表中显示两列,我相信最佳做法是该表还有一个唯一的自动递增字段。
注意:两个加入字段通常是唯一索引。
答案 2 :(得分:0)
您必须自己为此编写逻辑代码。您可以通过触发器实现它,并使用窗口函数(row_number()over(按父节点顺序分隔...)来使任务更容易。
您也可以让主键只是一个标识列(parent_id不让成为PK的一部分),并且有一个“Sequence_Num”列来跟踪int您想要使用每个parent_id重置。您甚至可以执行此操作,并仍在parent_id / sequence_num cols上设置聚簇索引。
恕我直言,第二种选择更好,因为它允许更大的灵活性,没有任何重大缺点。它还使窗口函数更容易编写,因为您可以通过代理键(标识列)进行排序,以在重新生成sequence_num时保留插入顺序。在这两种情况下,您都必须自己管理“sequenec_num”列的排序。