【问题标题】:How to save auto generated primary key Id in foreign key column in same table如何在同一张表的外键列中保存自动生成的主键 ID
【发布时间】:2017-10-14 09:48:26
【问题描述】:

表结构如下:

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 和插入语句?

【问题讨论】:

  • 好吧,在你的标题中你说 外键 但是你的代码中有一个,而且你没有显示你的表的所有列[Creator] [bigint] NOT NULL,,你可以edit你的问题并添加表结构并解释更多。
  • 我已经添加了表结构,我需要在 Creator 列中插入相同的 Id 值
  • 查看更新 Furqan。

标签: sql sql-server sql-server-2008 sql-server-2008-r2


【解决方案1】:

一种方法是使用序列而不是标识列。下面的脚本可能有同样的目的:

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

结果:

【讨论】:

    【解决方案2】:

    简短的回答是你不能这样做。我建议您的模型首先在逻辑上存在缺陷。您是否打算将所有实际数据库用户(例如,创建用户 ... 用于登录 ...)定义为 [Users] 中的行?你需要考虑一下——但典型的答案是否定的。如果答案是肯定的,那么您根本不需要创建者列,因为它是多余的。您所需要的只是创建日期——您可能应该为其定义一个默认值。

    但是,如果您想这样做,您需要分两步完成(并且您需要使列可以为空)。您插入一行(或多行),其中包含“真实”数据列的值。然后使用为 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) 并且下一个插入的值可能由于多种原因而跳转 - 例如错误和缓存/重新启动。最后,我想你会后悔用保留字命名一个表,因为引用它需要使用分隔符。减轻痛苦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-06
      • 2018-11-20
      • 1970-01-01
      • 1970-01-01
      • 2013-10-05
      • 1970-01-01
      • 2012-09-04
      相关资源
      最近更新 更多