How to INSERT into a table that uses sequential GUIDs as a primary key?

三世轮回 提交于 2019-12-23 09:01:28

问题


Here is a simplified version of the table I am looking at:

CREATE TABLE [dbo].[FrustratingTable]
(
    [Id] Uniqueidentifier NOT NULL
    , [SecondField] [datetime]
    , [ThirdField] varchar(128)
)

I want to insert new records into this table. I have tried 3 approaches:

INSERT INTO [dbo].[FrustratingTable] (Id, SecondField, ThirdField)
    SELECT newid() as Id, 
           '6/25/2015' as SecondField, 'Example' as ThirdField

This approach inserts, but the resulting key isn't a nice sequential GUID like the other ones in the table

INSERT INTO [dbo].[FrustratingTable] (Id, SecondField, ThirdField)
SELECT NEWSEQUENTIALID() as Id, '6/25/2015' as SecondField, 'Example' as ThirdField

This fails with error

The newsequentialid() built-in function can only be used in a DEFAULT expression for a column of type 'uniqueidentifier' in a CREATE TABLE or ALTER TABLE statement. It cannot be combined with other operators to form a complex scalar expression.

INSERT INTO [dbo].[FrustratingTable] (SecondField,ThirdField)
SELECT '6/25/2015' as SecondField, 'Example' as ThirdField

This fails with the error

Cannot insert the value NULL into column 'id', table 'mydatabase.dbo.frustratingtable'; column does not allow nulls. INSERT fails.

Is it possible to solve this without altering the table definition?


回答1:


You may be able to do this by way of using a table variable:

declare @t table (
    ID uniqueidentifier not null default newsequentialid(),
    SecondField datetime,
    ThirdField varchar(128)
)
insert into @t (SecondField,ThirdField)
    output inserted.ID,inserted.SecondField,inserted.ThirdField
    into FrustratingTable
values
('20150101','abc'),
('20150201','def'),
('20150301','ghi')

select * from FrustratingTable

Results:

Id                                   SecondField             ThirdField
------------------------------------ ----------------------- ------------
1FEBA239-091C-E511-9B2F-78ACC0C2596E 2015-01-01 00:00:00.000 abc
20EBA239-091C-E511-9B2F-78ACC0C2596E 2015-02-01 00:00:00.000 def
21EBA239-091C-E511-9B2F-78ACC0C2596E 2015-03-01 00:00:00.000 ghi

Since the table variable sets the value via a default, we're allowed to use NEWSEQUENTIALID().

Of course, for very large data sets, there's a penalty in temporarily having two copies of the data lurking around.


An alternative would be to use an older solution, called COMBs, which were used before NEWSEQUENTIALID() was introduced:

SELECT CAST(CAST(NEWID() AS BINARY(10)) + CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER)

Generates uniqueidentifiers with better locality than NEWID() by itself does.




回答2:


Ok, if first yout take the [IncrementGuid] function from this answer, then you can do something like this,

Fiddle Here

INSERT [dbo].[FrustratingTable]
SELECT
      [dbo].[IncrementGuid](MAX([Id])),
      '01/01/01',
      '3'
  FROM
      [dbo].[FrustratingTable];

Caveat:

Once you reviewed the function in the other answer, you'll agree, there must be a better way.

Change the code that needs the GUIDs to be sequential.




回答3:


ALTER TABLE FrustratingTable
ALTER COLUMN id uniqueidentifier not null default newsequentialid()


来源:https://stackoverflow.com/questions/31073409/how-to-insert-into-a-table-that-uses-sequential-guids-as-a-primary-key

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!