在两个表之间共享自增主键

10

你好,我想要创建两个表,每个表都有一个INT类型的"id"列,该列将自动递增,但我不希望两个表中的"id"列共用同一个数字。这被称为什么?什么是最佳方法?序列、迭代器、索引、增量器?

动机:我们正在从一种模式迁移到另一种模式,并且有一个网页可以读取这两个表并显示(int) ID,但我不能让相同的ID用于两个表。

我使用的是SQL Server 9.0.3068.

谢谢!


你能解释一下为什么需要这样做吗?也许有更好的设计方案,不需要使用GUID。 - Rob Allen
9个回答

14

只需将身份增量配置为> 1,例如表一使用IDENTITY(1, 10)[1,11,21 ...],表二使用IDENTITY(2, 10)[2,12,22 ...]。这样做也会为以后需要时提供一些扩展的空间。


我应该如何做到这一点?有没有使用PHPMyadmin的方法可以实现这个? - everconfusedGuy
在进行此操作时,还应考虑使用bigint。 - Sql Surfer
请注意,使用 SET IDENTITY_INSERT 可以插入一个不会被自动编号分配的值。您可以通过添加检查约束来防止这种情况:alter table foo add check (Id % 10 = 0)。该约束将确保插入的值符合特定条件。 - R. Schreurs

3

如果我理解正确的话,我认为使用GUID是最直接的方法。

SELECT NEWID()

抱歉,我应该提到它需要是一个整数。 - user24881

2

使用具有GUID (全局唯一标识符)类型的列。它是16字节,在每行中始终是唯一的。

只需注意,与普通整数键相比,性能会受到显着影响。


1

使用另一张表,其ID键类型为int,默认值为1,称为KeyID或其他名称。

编写一个存储过程来检索该值,加1,然后更新KeyID,最后将其返回给正在更新新唯一键的两个表的存储过程。

这将确保ID是int类型,并且在使用存储过程生成新ID的表集之间是唯一的。


1

你可以在第三个表中定义一个IDENTITY列,用它生成ID值,但是你总是要回滚你对表的任何插入(以避免使其增长)。回滚事务不会回滚ID被生成的这一事实。

我不是Microsoft SQL Server的经常用户,所以请原谅任何语法上的错误。但我想到的类似以下内容:

CREATE TABLE AlwaysRollback (
  id IDENTITY(1,1)
);

BEGIN TRANSACTION;
INSERT INTO AllwaysRollBack () VALUES ();
ROLLBACK TRANSACTION;

INSERT INTO RealTable1 (id, ...) VALUES (SCOPE_IDENTITY(), ...);

BEGIN TRANSACTION;
INSERT INTO AllwaysRollBack () VALUES ();
ROLLBACK TRANSACTION;

INSERT INTO RealTable2 (id, ...) VALUES (SCOPE_IDENTITY(), ...);

0
如果您确实需要使用int类型,并且有一个自增的数字,我以前做过的方法是将id字段的自增函数更改为另一个表的序列。我不太确定在ms sql或my sql中是否适用,但在pgsql中,这意味着您会在sql中拥有这个字段。
 id integer NOT NULL DEFAULT nextval('table_two_seq'::regclass),

其中table_two_sequence是另一张表的序列函数。然后通过插入一些数据来测试它。如果在MS SQL中无法正常工作,我真的很抱歉,因为我尽量避免使用它。如果失败了,GUID就是最好的方法,正如其他人所提到的。或者在您使用的代码中插入一个算法,但可能会变得混乱。

或者,考虑将数据放在一个表中,这将是解决问题的一种方法。如果需要,您可以拥有一个模拟两个表的视图。只是一个想法。

希望我已经帮到您了。


0
从 SQL Server 2012 开始,您可以声明一个序列对象https://msdn.microsoft.com/en-us/library/ff878091.aspx,这正是您所需的。
使用包含下一个序列值和存储过程以原子方式选择该值并递增的表来模拟序列对象应该相当简单。[你可能想使用函数,但是函数不能有副作用。]
如何尝试这个黑客技巧?创建一个表(MySequence),其中包含两列:自增列(SequenceValue)和虚列(DummyValue),然后使用此存储过程获取新的序列值。该表中仅有的一行将是检索到的最后一个序列值。
CREATE PROCEDURE GetNextValue 
AS
BEGIN
    DECLARE @value int = null;

    -- Insert statements for procedure here
    INSERT into MySequence (DummyValue) Values (null);

    SET @value = SCOPE_IDENTITY();

    DELETE from MySequence where SequenceValue <> @value

    SELECT @value as Sequence

    return @value
END

要使用该序列,您需要管理对目标表的插入操作--触发器可能是一个不错的选择。


0

我不知道你会怎么称呼它。

如果不想使用 GUID 或单独的表,你也可以创建一个函数,该函数查看两个表的 id 的最大值并将其加一(或类似的操作)。

然后在两个表的插入触发器中调用该函数。


0

我个人喜欢GUID解决方案,但这里有一个可行的选择。

许多解决此问题的方法避免使用GUID,而是使用老式整数。这在合并复制情况下也很常见,其中许多卫星站点与主站点合并,需要避免键冲突。

如果GUID对您不起作用,而您绝对必须使用int、bigint或类似类型,您可以始终只使用IDENTITY列,并为每个表设置不同的SEED值。这些数据类型具有非常广泛的范围,如果您只想要两个分段,将其分成可用的段并不太难。例如,基本int的范围从-2^31(-2,147,483,648)到2^31-1(2,147,483,647)。这对于客户表来说已经足够了。

Transact-SQL参考(SQL Server 2000) int、bigint、smallint和tinyint

示例:

--Create table with a seed of 1 billion and an increment of 1
CREATE TABLE myTable
(
primaryKey int IDENTITY (1000000000, 1),
columnOne varchar(10) NOT NULL
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接