如何保存自动生成的主键标识的外键列在同一个表
问题描述:
以下是表结构:如何保存自动生成的主键标识的外键列在同一个表
CREATE TABLE [User] (
[Id] bigint identity(1,1) not null,
[FirstName] nvarchar(100) not null,
[LastName] nvarchar(100) not null,
[Title] nvarchar(5) null,
[UserName] nvarchar(100) not null,
[Password] nvarchar(100) not null,
[Inactive] bit null,
[Created] Datetime not null,
[Creator] bigint not null,
[Modified] DateTime null,
[Modifier] bigint null
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[Id] Asc
)
);
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[FK_User_Creator]') AND parent_object_id = OBJECT_ID(N'[User]'))
ALTER TABLE [User] ADD CONSTRAINT [FK_User_Creator] FOREIGN KEY([Creator]) REFERENCES [User]([Id])
GO
INSERT INTO [User] (Creator) Values ([Id] ?)
这是一个情况下表为空,第一个用户是要在表中添加。否则,我没有问题。
如何在插入语句的同时在创建者列中插入Id?
答
一种方法可能是使用序列而不是标识列。下面的脚本可以达到相同的目的:
CREATE SEQUENCE dbo.useridsequence
AS int
START WITH 1
INCREMENT BY 1 ;
GO
CREATE TABLE [User] (
[Id] bigint DEFAULT (NEXT VALUE FOR dbo.useridsequence) ,
[FirstName] nvarchar(100) not null,
[LastName] nvarchar(100) not null,
[Title] nvarchar(5) null,
[UserName] nvarchar(100) not null,
[Password] nvarchar(100) not null,
[Inactive] bit null,
[Created] Datetime not null,
[Creator] bigint DEFAULT NEXT VALUE FOR dbo.useridsequence ,
[Modified] DateTime null,
[Modifier] bigint null
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[Id] Asc
)
);
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[FK_User_Creator]') AND parent_object_id = OBJECT_ID(N'[User]'))
ALTER TABLE [User] ADD CONSTRAINT [FK_User_Creator] FOREIGN KEY([Creator]) REFERENCES [User]([Id])
GO
INSERT INTO [User]
(
-- Id -- this column value is auto-generated
FirstName,
LastName,
Title,
UserName,
[Password],
Inactive,
Created,
Creator,
Modified,
Modifier
)
VALUES
(
'Foo',
'Bar',
'Title',
'UserName ',
'Password',
0,
GETDATE(),
DEFAULT,
GETDATE(),
1
)
SELECT * FROM [User] AS u
答
简短的回答是,你不能这样做。我建议你的模型首先在逻辑上是有缺陷的。您是否打算将[用户]中的所有实际数据库用户(例如,创建用户...用于登录...)定义为行?你需要考虑这一点 - 但典型的答案是否定的。如果答案是肯定的,那么你完全不需要创建者列,因为它是多余的。所有你需要的是创建的日期 - 你可能应该定义一个默认值。
但是,如果你想这样做,你需要分两步来完成(你需要使列可以为空)。您为“真实”数据列插入一行(或多行)值。然后使用为id生成的标识值更新这些相同的行。一个例子显示了不同的方式来做到这一点
use tempdb;
set nocount on;
CREATE TABLE dbo.[user] (
[user_id] smallint identity(3,10) not null primary key,
[name] nvarchar(20) not null,
[active] bit not null default (1),
[created] Datetime not null default (current_timestamp),
[creator] smallint null
);
ALTER TABLE dbo.[user] ADD CONSTRAINT [fk_user] FOREIGN KEY(creator) REFERENCES dbo.[user](user_id);
GO
-- add first row
insert dbo.[user] (name) values ('test');
update dbo.[user] set creator = SCOPE_IDENTITY() where user_id = SCOPE_IDENTITY()
-- add two more rows
declare @ids table (user_id smallint not null);
insert dbo.[user] (name) output inserted.user_id into @ids
values ('nerk'), ('pom');
update t1 set creator = t1.user_id
from @ids as newrows inner join dbo.[user] as t1 on newrows.user_id = t1.user_id;
select * from dbo.[user] order by user_id;
-- mess things up a bit
delete dbo.[user] where name = 'pom';
-- create an error, consume an identity value
insert dbo.[user](name) values (null);
-- add 2 morerows
delete @ids;
insert dbo.[user] (name) output inserted.user_id into @ids
values ('nerk'), ('pom');
update t1 set creator = t1.user_id
from @ids as newrows inner join dbo.[user] as t1 on newrows.user_id = t1.user_id;
select * from dbo.[user] order by user_id;
drop table dbo.[user];
而且我改变了身份规范,以演示一些开发人员意识到的东西。它并不总是被定义为(1,1),并且下一个插入的值可能由于多种原因跳转 - 例如错误和缓存/重新启动。最后,我认为你会后悔用一个保留字命名表,因为引用它将需要使用分隔符。减轻痛苦。
那么,在您的标题,你说_foreign KEY_但有一个在你的代码,你也没有显示的所有列你的表格[[Creator] [bigint] NOT NULL,',你可以[编辑](https://stackoverflow.com/posts/46743153/edit)你的问题并添加表格结构并解释更多。 – Sami
我添加了表格结构,我需要在创建者列中插入相同的Id值 –
查看更新Furqan。 – Sami