SCOPE_IDENTITY () para GUIDs?

94

Alguém pode me dizer se há um equivalente de SCOPE_IDENTITY()quando usar GUIDs como uma chave primária no SQL Server?

Não quero criar o GUID primeiro e salvar como uma variável, pois estamos usando GUIDs sequenciais como nossas chaves primárias.

Alguma ideia sobre qual a melhor maneira de recuperar a última chave primária GUID inserida?

bplus
fonte

Respostas:

98

Você pode obter o GUID de volta usando OUTPUT. Isso também funciona quando você está inserindo vários registros.

CREATE TABLE dbo.GuidPk (
    ColGuid uniqueidentifier NOT NULL DEFAULT NewSequentialID(),
    Col2    int              NOT NULL
)
GO

DECLARE @op TABLE (
    ColGuid uniqueidentifier
)

INSERT INTO dbo.GuidPk (
    Col2
)
OUTPUT inserted.ColGuid
INTO @op
VALUES (1)

SELECT * FROM @op

SELECT * FROM dbo.GuidPk

Referência: Explorando a cláusula OUTPUT do SQL 2005

Rob Garrison
fonte
2
Como a anishmarokey menciona, você deve usar NewSequentialID () para gerar seus GUIDs e não NewID ().
Rob Garrison,
@RobGarrison Imo, GUID como um PK só é realmente vantajoso sobre int / bigint em sistemas distribuídos. Se você está acessando o banco de dados para buscar um ID, você também pode usar int / bigint. NewSequentialID () só pode ser usado como uma restrição padrão (você não pode inserir explicitamente usando NewSequentialID () por exemplo). Como tal, acho que na grande maioria dos cenários em que você pode usá-lo, você deveria fazer as coisas de maneira diferente.
Shiv
A OUTPUTcláusula fornece um erro em qualquer tabela que tenha um gatilho de inserção anexado.
Cobus Kruger
60

Não há equivalente SCOPE_IDENTITY () ao usar GUIDs como chaves primárias, mas você pode usar a cláusula OUTPUT para obter um resultado semelhante. Você não precisa usar uma variável de tabela para a saída.

CREATE TABLE dbo.GuidTest (
    GuidColumn uniqueidentifier NOT NULL DEFAULT NewSequentialID(),
    IntColumn int NOT NULL
)

GO

INSERT INTO GuidTest(IntColumn)
OUTPUT inserted.GuidColumn
VALUES(1)

O exemplo acima é útil se você deseja ler o valor de um cliente .Net. Para ler o valor de .Net, você apenas usaria o método ExecuteScalar.

...
string sql = "INSERT INTO GuidTest(IntColumn) OUTPUT inserted.GuidColumn VALUES(1)";
SqlCommand cmd = new SqlCommand(sql, conn);
Guid guid = (Guid)cmd.ExecuteScalar();
...
Daniel
fonte
9

você deseja usar NEWID ()

    declare @id uniqueidentifier
    set @id  = NEWID()
    INSERT INTO [dbo].[tbl1]
           ([id])
     VALUES
           (@id)

    select @id

mas o problema do índice agrupado está lá no GUID. leia este também NEWSEQUENTIALID () . Estas são minhas idéias, pense antes de usar o GUID como chave primária . :)

anishMarokey
fonte
10
"A função embutida newsequentialid () só pode ser usada em uma expressão DEFAULT para uma coluna do tipo 'uniqueidentifier' em uma instrução CREATE TABLE ou ALTER TABLE. Ela não pode ser combinada com outros operadores para formar uma expressão escalar complexa."
Scott Whitlock
4
CREATE TABLE TestTable(KEY uniqueidentifier, ID VARCHAR(100), Name VARCHAR(100), Value tinyint);
Declare @id uniqueidentifier ;  
DECLARE @TmpTable TABLE (KEY uniqueidentifier);     
INSERT INTO [dbo].[TestTable]
    ([ID], [Name], Value])           
    OUTPUT INSERTED.KEY INTO @TmpTable           
    VALUES(@ID, @Name, @Value);           
SELECT @uniqueidentifier = KEY FROM @TmpTable; 
DROP TABLE TestTable;
Joe
fonte
2

Usando este thread como um recurso, criei o seguinte para uso em um gatilho:

DECLARE @nextId uniqueIdentifier;
DECLARE @tempTable TABLE(theKey uniqueIdentifier NOT NULL DEFAULT NewSequentialID(), b int);
INSERT INTO @tempTable (b) Values(@b);
SELECT @nextId = theKey from @tempTable;

Pode ajudar outra pessoa a fazer a mesma coisa. Curioso se alguém tem algo ruim a dizer sobre desempenho, se isso não é uma boa ideia ou não.

TravisWhidden
fonte
depois de reler a pergunta, percebi que isso realmente não responde à pergunta dos usuários ... mas ainda pode ser útil para alguém porque as respostas semelhantes são o mesmo tipo de resposta.
TravisWhidden