INSERT, and get the auto-incremented value - sql

Consider the following table:
create table language (
id integer generated always as identity (START WITH 1, INCREMENT BY 1),
name long varchar,
constraint language_pk primary key (id)
);
To which I'd insert an entry this way.
insert into language(name) values ('value');
How does one know what value for id was created? Just doing a SELECT using the name field is not valid, because there can be duplicate entries.

Through plain SQL:
insert into language(name) values ('value');
SELECT IDENTITY_VAL_LOCAL();
See the manual for details: http://db.apache.org/derby/docs/10.7/ref/rrefidentityvallocal.html
When doing this from a Java class (through JDBC) you can use getGeneratedKeys() after "requesting" them with the approriate executeUpdate() method.

You use the JDBC method
st.execute(sql, Statement.RETURN_GENERATED_KEYS);
ResultSet keys = st.getGeneratedKeys();
as documented in the Derby manual.
See also Javadocs: DatabaseMetaData#supportsGetGeneratedKeys()
and Statement#getGeneratedKeys()

You could execute this statement (NB, not 100% sure this syntax is correct for Derby:
SELECT TOP 1 id FROM language ORDER BY id DESC
To find the last inserted ID.
Alternative for Derby:
SELECT MAX(id) from language
Obviously this will only be accurate if no other inserts (including inserts by other users) have happened between your insert and select.
See also this discussion:

Related

How to insert a row if not exists otherwise select and return its ID in both cases in MariaDB?

I have a table with ID primary key (autoincrement) and a unique column Name. Is there an efficient way in MariaDB to insert a row into this table if the same Name doesn't exist, otherwise select the existing row and, in both cases, return the ID of the row with this Name?
Here's a solution for Postgres. However, it seems MariaDB doesn't have the RETURNING id clause.
What I have tried so far is brute-force:
INSERT IGNORE INTO services (Name) VALUES ('JohnDoe');
SELECT ID FROM services WHERE Name='JohnDoe';
UPDATE: MariaDB 10.5 has RETURNING clause, however, the queries I have tried so far throw a syntax error:
WITH i AS (INSERT IGNORE INTO services (`Name`) VALUES ('John') RETURNING ID)
SELECT ID FROM i
UNION
SELECT ID FROM services WHERE `Name`='John'
For a single row, assuming id is AUTO_INCREMENT.
INSERT INTO t (name)
VALUES ('JohnDoe')
ON DUPLICATE KEY id = LAST_INSERT_ID(id);
SELECT LAST_INSERT_ID();
That looks kludgy, but it is an example in the documentation.
Caution: Most forms of INSERT will "burn" auto_inc ids. That is, they grab the next id(s) before realizing that the id won't be used. This could lead to overflowing the max auto_inc size.
It is also wise not to put the normalization inside the transaction that does the "meat" of the code. It ties up the table unnecessarily long and runs extra risk of burning ids in the case of rollback.
For batch updating of a 'normalization' table like that, see my notes here: http://mysql.rjweb.org/doc.php/staging_table#normalization (It avoids burning ids.)

SQL - Inserting a row and returning primary key

I have inserted a row with some data in a table where a primary key is present. How would one "SELECT" the primary key of the row one just inserted?
I should have been more specific and mentioned that I'm currently
using SQLite.
For MS SQL Server:
SCOPE_IDENTITY() will return you the last generated identity value within your current scope:
SELECT SCOPE_IDENTITY() AS NewID
For SQL Server 2005 and up, and regardless of what type your primary key is, you could always use the OUTPUT clause to return the values inserted:
INSERT INTO dbo.YourTable(col1, col2, ...., colN)
OUTPUT Inserted.PrimaryKey
VALUES(val1, val2, ....., valN)
SQL Server:
You can use ##IDENTITY. After an insert statement, you can run:
select ##identity
This will give you the primary key of the record you just inserted. If you are planning to use it later, I suggest saving it:
set #MyIdentity = ##identity
If you are using this in a stored procedure and want to access it back in your application, make sure to have nocount off.
For MySQL, use LAST_INSERT_ID()
http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
You should also be able to start a transaction, insert the row, and select the row using some field that has a unique value that you just inserted, like a timestamp or guid. This should work in pretty much any RDBMS that supports transactions, as long as you have a good unique field to select the row with.
If you need to retrieve the new index in MS SQL when there are triggers on the table then you have to use a little workaround. A simple OUTPUT will not work. You have to do something like this (in VB.NET):
DECLARE #newKeyTbl TABLE (newKey INT);
INSERT INTO myDbName(myFieldName) OUTPUT INSERTED.myKeyName INTO #newKeyTbl VALUES('myValue'); " & _
SELECT newKey FROM #newKeyTbl;"
If using .NET, then the return value from this query can be directly cast to an integer (you have to call "ExecuteScalar" on the .NET SqlCommand to get the return).
For SQLite:
SELECT [Column_1], [Column_2],... [Column_n]
FROM [YourTable]
WHERE rowid = (SELECT last_insert_rowid())
whereas:
Column_1, Column_2,... Column_n: are the primary key of YourTable.
If you'd created YourTable with primary key replaced rowid (i.e. one column pk defined as INTEGER PRIMARY KEY) you just use:
SELECT last_insert_rowid()
Which is a common case.
Finally, this wont work for WITHOUT_ROWID tables.
Please Check:
https://www.sqlite.org/lang_corefunc.html#last_insert_rowid
For PostgreSQL,
INSERT INTO tablename (col1, col2, ...)
VALUES (val1, val2, ...)
RETURNING idcol;
The optional RETURNING clause causes INSERT to compute and return value(s) based on each row actually inserted (or updated, if an ON CONFLICT DO UPDATE clause was used). This is primarily useful for obtaining values that were supplied by defaults, such as a serial sequence number. However, any expression using the table's columns is allowed.
https://www.postgresql.org/docs/current/sql-insert.html
For Postgresql:
SELECT CURRVAL(pg_get_serial_sequence('schema.table','id'))
Source: PostgreSQL function for last inserted ID
select MAX(id_column) from table
That, in theory, should return you that last inserted id. If it's a busy database with many inserts going on it may not get the one you just did but another.
Anyhow, an alternative to other methods.

Primary key value after insertion of row in SQL Server 2005

In SQL Server 2005 I am inserting a row into a table using a stored procedure and I want to fetch the new primary key value just after inserting that row. I am using following approach to get primary key value after insertion row
Create Proc Sp_Test
#testEmail varchar(20)=null,-- Should be Unique
#testName varchar(20)=null -- Should be Unique
as
begin
insert into tableTest (testUserEmail,testUserName)values (#testValue,#testName)
select MAX(ID) from tableTest --ID is Primary Key
--or
select ID from tableTest where testUserEmail =#testValue and testUserName = #testName
--or
select SCOPE_IDENTITY() as ID
end
Please suggest me which approach is better to perform described task.
By all means - use the SCOPE_IDENTITY() if your ID column is an INT IDENTITY - only that will give you the correct results!
The first approach with the MAX(ID) will fail terribly if you have multiple clients inserting rows almost at the same time - you'll get false results back. Don't use that!
The third approach might fail if another entry with the same values for E-Mail and name already exists.
Also, as a side-note: you should never use sp_ as your prefix! This is a Microsoft-reserved prefix and has downsides in terms of performance - use something else.
If you have an Identity column as primary key you should use SCOPE_IDENTITY()
You could also use the OUTPUT Clause to return the ID.
insert into tableTest(testUserEmail,testUserName)
output inserted.ID
values (#testValue, #testName)

Atomic INSERT/SELECT in HSQLDB

I have the following hsqldb table, in which I map UUIDs to auto incremented IDs:
SHORT_ID (BIG INT, PK, auto incremented) | UUID (VARCHAR, unique)
Create command:
CREATE TABLE mytable (SHORT_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, UUID VARCHAR(36) UNIQUE)
In order to add new pairs concurrently, I want to use the atomic MERGE INTO statement. So my (prepared) statement looks like this:
MERGE INTO mytable USING (VALUES(CAST(? AS VARCHAR(36)))) AS v(x) ON mytable.UUID = v.x WHEN NOT MATCHED THEN INSERT VALUES v.x
When I execute the statement (setting the placeholder correctly), I always get a
Caused by: org.hsqldb.HsqlException: row column count mismatch
Could you please give me a hint, what is going wrong here?
Thanks in advance.
Epilogue
I reported this behavior as a bug, and it is today (2010-05-25) fixed in the hsqldb SVN repository, per hsqldb-Bugs-2989597. (Thanks, hsqldb!)
Updated Answer
Neat one! Here's what I got to work under HSQLDB 2.0.0rc9, which supports the syntax and the error message you posted:
MERGE INTO mytable
USING (SELECT 'a uuid' FROM dual) AS v(x) -- my own "DUAL" table
ON (mytable.UUID = v.x)
WHEN NOT MATCHED THEN INSERT
VALUES (NULL, x) -- explicit NULL for "SHORT_ID" :(
Note, I could not convince 2.0.0rc9 to accept ... THEN INSERT (UUID) VALUES (x), which is IIUC a perfectly acceptable and clearer specification than the above. (My SQL knowledge is hardly compendious, but this looks like a bug to me.)
Original Answer
You appear to be INSERTing a single value (a 1-tuple) into a table with more than one column. Perhaps you can modify the end of your statement to read:
... WHEN NOT MATCHED INSERT ("UUID") VALUES (v.x)
I got same problems but solve in few minutes.
Its occur when datavalues and table structure are not same.Add explicit (NULL) in your empty column value.
Like i created table
TestCase table:
ID TESTCASEID DESCRIPTION
but your insertion statement you donot want to add any description for any testcase description then you have to explicite in insertion statement you have to set null value for description

iSeries DB2 - Is there any way to select the identity value from an insert statement?

I know we're rare, us poor folk that are using iSeries for DB2/AS400, but I'm hoping someone can answer this simple question. Is there any way to return the identity value from an insert statement without using two lines of SQL? I'm being forced to use inline SQL in C# to perform an insert, and then I need to use the identity generated for the insert for something later on. Simply put, I need the iSeries DB2 equivalent of Oracle's "RETURNING." I.e.,
INSERT INTO AwesomeTable (column1, column2, etc.)
VALUES (value1, value2, etc.)
RETURNING something;
Anyone? Thanks in advance.
EDIT: Unless someone knows of a way I can execute two lines of SQL in one IBM.Data.DB2.iSeries.iDB2Command (not a stored proc), I would like to do this all in one line of SQL
I am not sure of iSeries, but the following worked on db2v8.1:
Consider 'ID' is the name of your identity column. The following stmt will return the newly generated id (the same one that gets inserted by the insert stmt):
SELECT ID FROM FINAL TABLE (
INSERT INTO AwesomeTable (column1, column2, etc.)
VALUES (value1, value2, etc.)
)
Some explanation I found on the publib site: (I used it for reference to test my query above)
/* The following SELECT statement references an INSERT statement in its
FROM clause. It inserts an employee record from host variables into
table company_b. The current employee ID from the cursor is selected
into the host variable new_id. The keywords FROM FINAL TABLE
determine that the value in new_id is the value of ID after the
INSERT statement is complete.
Note that the ID column in table company_b is generated and without
the SELECT statement an additional query would have to be made in
order to retreive the employee's ID number.
*/
EXEC SQL SELECT ID INTO :new_id
FROM FINAL TABLE(INSERT INTO company_b
VALUES(default, :name, :department, :job, :years, :salary,
:benefits, :id));
Hope this helps :)
You need to use the IDENTITY_VAL_LOCAL scalar function. From the IBM documentation:
IDENTITY_VAL_LOCAL is a
non-deterministic function that
returns the most recently assigned
value for an identity column.
Example:
CREATE TABLE EMPLOYEE
(EMPNO INTEGER GENERATED ALWAYS AS IDENTITY,
NAME CHAR(30),
SALARY DECIMAL(5,2),
DEPT SMALLINT)
INSERT INTO EMPLOYEE
(NAME, SALARY, DEPTNO)
VALUES('Rupert', 989.99, 50)
SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1
Here's an example :
CREATE TABLE AUTOINC (
AUTO91 INTEGER GENERATED ALWAYS AS IDENTITY,
SCDS91 CHAR(35) NOT NULL DEFAULT '',
MCLD91 DECIMAL(3,0) NOT NULL DEFAULT 0,
CONSTRAINT PK_AUTOINC PRIMARY KEY(AUTO91));
// Notice the default keyword where the auto increment field is.
insert into AUTOINC Values( default ,'SYSC' , 0 )
// And using the function to return the last identity column value.
// Note: fetch first row only.
select **IDENTITY_VAL_LOCAL**() from AUTOINC **fetch first row only**