Search code examples
advantage-database-server

Implementing a unique surrogate key in Advantage Database Server


I've recently taken over support of a system which uses Advantage Database Server as its back end. For some background, I have years of database experience but have never used ADS until now, so my question is purely about how to implement a standard pattern in this specific DBMS.

There's a stored procedure which has been previously developed which manages an ID column in this manner:

@ID = (SELECT ISNULL(MAX(ID), 0) FROM ExampleTable);
@ID = @ID + 1;

INSERT INTO Example_Table (ID, OtherStuff)
VALUES (@ID, 'Things');

--Do some other stuff.

UPDATE ExampleTable
SET AnotherColumn = 'FOO'
WHERE ID = @ID;

My problem is that I now need to run this stored procedure multiple times in parallel. As you can imagine, when I do this, the same ID value is getting grabbed multiple times.

What I need is a way to consistently create a unique value which I can be sure will be unique even if I run the stored procedure multiple times at the same moment. In SQL Server I could create an IDENTITY column called ID, and then do the following:

INSERT INTO ExampleTable (OtherStuff)
VALUES ('Things');

SET @ID = SCOPE_IDENTITY(); 

ADS has autoinc which seems similar, but I can't find anything conclusively telling me how to return the value of the newly created value in a way that I can be 100% sure will be correct under concurrent usage. The ADS Developer's Guide actually warns me against using autoinc, and the online help files offer functions which seem to retrieve the last generated autoinc ID (which isn't what I want - I want the one created by the previous statement, not the last one created across all sessions). The help files also list these functions with a caveat that they might not work correctly in situations involving concurrency.

How can I implement this in ADS? Should I use autoinc, some other built-in method that I'm unaware of, or do I genuinely need to do as the developer's guide suggests, and generate my unique identifiers before trying to insert into the table in the first place? If I should use autoinc, how can I obtain the value that has just been inserted into the table?


Solution

  • You use LastAutoInc(STATEMENT) with autoinc.

    From the documentation (under Advantage SQL->Supported SQL Grammar->Supported Scalar Functions->Miscellaneous):

    LASTAUTOINC(CONNECTION|STATEMENT)

    Returns the last used autoinc value from an insert or append. Specifying CONNECTION will return the last used value for the entire connection. Specifying STATEMENT returns the last used value for only the current SQL statement. If no autoinc value has been updated yet, a NULL value is returned.

    Note: Triggers that operate on tables with autoinc fields may affect the last autoinc value.

    Note: SQL script triggers run on their own SQL statement. Therefore, calling LASTAUTOINC(STATEMENT) inside a SQL script trigger would return the lastautoinc value used by the trigger's SQL statement, not the original SQL statement which caused the trigger to fire. To obtain the last original SQL statement's lastautoinc value, use LASTAUTOINC(CONNECTION) instead.

    Example: SELECT LASTAUTOINC(STATEMENT) FROM System.Iota