ID generation in Oracle - sql

I'm trying to create a table in Oracle as follows:
create table person (
person_id number(5) generated always as identity
minvalue 1
maxvalue 99999
increment by 1 start with 1
cycle
cache 10,
firstname varchar(10),
lastname varchar(10));
This works all fine, but when I try something like this:
insert into person
values ('firstname', 'lastname');
I'm getting an error. When I try putting in a number where the ID should be, I get a different error.
I'm confused because I originally thought that formatting the person_id in this way automatically generated unique ID values, so that I wouldn't be able to put them in.
I'm also a bit confused on how this all fits into JDBC. If I'm working with Java and I insert a tuple into such a table, how am I able to get the generated ID into my Java program? I can't search by first and last name, because there could be two people with the same name.

You need to list the columns for an insert:
insert into person(firstname, lastname)
values ('firstname', 'lastname');
The fact that the column is generated doesn't affect the syntax of the insert. So, with no columns, the insert is the same as:
insert into person(person_id, firstname, lastname)
values ('firstname', 'lastname');
And with two values and three columns, you are getting an error.

Related

How to store a return value of an SQL query inside a variable

Given a users and a roles table, I want to write an SQL statement, which inserts a new row into the users table and associates a row of the roles table with it.
This is what I have tried:
INSERT INTO users(firstname, lastname) VALUES ('John', 'Smith') RETURNING id;
INSERT INTO roles(role, user_id)
VALUES ('ROLE_USER', id);
The id used in the last line is not yet associated with the return value of the first line. Can someone explain to me how I could store the return type of the first line inside a variable and then use it in my last line?
I have come across the DECLARE keyword, but I am not sure this works with every kind of database. I am using a postgres DB. When using DECLARE #VariableName, the # gets marked as wrong syntax in my db-migrate script.
You can use a data modifying CTE:
with new_user as (
INSERT INTO users(firstname, lastname)
VALUES ('John', 'Smith')
RETURNING id
)
INSERT INTO roles(role, user_id)
SELECT 'ROLE_USER', id
FROM new_user;

Hive inserting max+1 into same table not working

i have a scenario ...
i have a table called sample with three columns:
id, name, address
where id is a unique auto increment column. here is my data:
id name address
1 john LA
2 peter. VS
my next column would be 3, 'smith', 'vegas'
i tried like this:
insert into sample select c1 as id from (select max(id)+1 from sample) c1, 'smith' as name , 'vegas' as address;
getting Error: Error compiling statement: FAILED: SemanticException Error in parsing (sttae=402000,code=40000)
i have tried for udf for auto increment column but no luck.
Hive (alas) doesn't support auto-increments. You can implement this as:
insert into sample (id, name, address)
select coalesce(max(id) + 1, 1), 'smith' as name , 'vegas' as address
from sample c1;
That said, I strongly recommend that you don't do this. Two inserts running at the same time will (likely) see the same maximum value -- and insert the same value for the id. To get around this, you would need to lock the entire table for each insert. And that is quite expensive.
Use UUIDs and an insertion date instead.
It might be a syntax thing. since i dont have a hive instance to try out,
does this work?
insert
into sample
select max(id)+1 c1
,max('smith') as name
,max('vegas') as address
from sample

When inserting a tuple into a table in SQL, does the order of the attributes in the schema matter?

ie. if Students(id,name,major,gpa) is the schema, are the following 2 SQL queries valid?
INSERT
INTO Students(id,name,major,gpa)
VALUES (123, Joe, CPSC, 3.0)
INSERT
INTO Students(name,id,major,gpa)
VALUES (Mike, 505, CPSC, 4.0)
Yes both of the query are correct. And the Values will insert to the column in whatever format your INSERT INTO t_Tablename(column1,column2) is made.
Just to make a check you can do (Assume id is int and Name is varchar)
INSERT INTO Students(id, Name)
VALUES("testString", 1)
which will give you an error, since you're trying to insert a string value to id which accepts an int and vice versa
Yes, the two following queries are Valid. Since you keep the order of your attributes values as described in Students(column1,column2), the query will be ok.
As long as the order in the INTO expression equates to the order in the VALUES expression, that is all that is required. The column list in the INTO expression determines both which columns you're specifying values for and the order the values will appear in the VALUES expression. The first column gets the first value, the second gets the second value, and so on.
If you neglect to specify the column list in the INTO expression, most RDBMSs will assume that the columns in the VALUES expression are in the ordinal order of columns in the table itself. That is, if you do this:
INSERT INTO Students
VALUES (123, Joe, CPSC, 3.0)
Then you better have done something like this:
CREATE TABLE Students (id int, name varchar(30), major varchar(30), gpa numeric(3,2))
That's the only time that the order of columns in the table itself actually matters to an INSERT statement.

Retrieve inserted row ID in SQL

How do I retrieve the ID of an inserted row in SQL?
Users Table:
Column | Type
--------|--------------------------------
ID | * Auto-incrementing primary key
Name |
Age |
Query Sample:
insert into users (Name, Age) values ('charuka',12)
In MySQL:
SELECT LAST_INSERT_ID();
In SQL Server:
SELECT SCOPE_IDENTITY();
In Oracle:
SELECT SEQNAME.CURRVAL FROM DUAL;
In PostgreSQL:
SELECT lastval();
(edited: lastval is any, currval requires a named sequence)
Note: lastval() returns the latest sequence value assigned by your session, independently of what is happening in other sessions.
In SQL Server, you can do (in addition to the other solutions already present):
INSERT INTO dbo.Users(Name, Age)
OUTPUT INSERTED.ID AS 'New User ID'
VALUES('charuka', 12)
The OUTPUT clause is very handy when doing inserts, updates, deletes, and you can return any of the columns - not just the auto-incremented ID column.
Read more about the OUTPUT clause in the SQL Server Books Online.
In Oracle and PostgreSQL you can do this:
INSERT INTO some_table (name, age)
VALUES
('charuka', 12)
RETURNING ID
When doing this through JDBC you can also do that in a cross-DBMS manner (without the need for RETURNING) by calling getGeneratedKeys() after running the INSERT
I had the same need and found this answer ..
This creates a record in the company table (comp), it the grabs the auto ID created on the company table and drops that into a Staff table (staff) so the 2 tables can be linked, MANY staff to ONE company. It works on my SQL 2008 DB, should work on SQL 2005 and above.
===========================
CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]
#comp_name varchar(55) = 'Big Company',
#comp_regno nchar(8) = '12345678',
#comp_email nvarchar(50) = 'no1#home.com',
#recID INT OUTPUT
-- The '#recID' is used to hold the Company auto generated ID number that we are about to grab
AS
Begin
SET NOCOUNT ON
DECLARE #tableVar TABLE (tempID INT)
-- The line above is used to create a tempory table to hold the auto generated ID number for later use. It has only one field 'tempID' and its type INT is the same as the '#recID'.
INSERT INTO comp(comp_name, comp_regno, comp_email)
OUTPUT inserted.comp_id INTO #tableVar
-- The 'OUTPUT inserted.' line above is used to grab data out of any field in the record it is creating right now. This data we want is the ID autonumber. So make sure it says the correct field name for your table, mine is 'comp_id'. This is then dropped into the tempory table we created earlier.
VALUES (#comp_name, #comp_regno, #comp_email)
SET #recID = (SELECT tempID FROM #tableVar)
-- The line above is used to search the tempory table we created earlier where the ID we need is saved. Since there is only one record in this tempory table, and only one field, it will only select the ID number you need and drop it into '#recID'. '#recID' now has the ID number you want and you can use it how you want like i have used it below.
INSERT INTO staff(Staff_comp_id)
VALUES (#recID)
End
-- So there you go. I was looking for something like this for ages, with this detailed break down, I hope this helps.

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**