Get value of index using PostgreSQL - java

I have one database that has two tables.
One table (Table A) has 3 columns:
idpms serial NOT NULL,
iduser integer NOT NULL,
iduser2 integer NOT NULL,
And the other (Table B) 3 columns
idmessage serial NOT NULL,
idpms integer NOT NULL,
text character varying(255),
I'm using Java to manage my database.
First, table A is updated with the values of user one and user two.
With the idpms values generated when I insert this data, Table B is updated with idpms and text
I have two questions:
How can I retrieve the value of idpms after inserting data in Table A?
In Java, can I somehow extract the idpms and cast it to an int?

Q1 :Yes.
Q2 :Yes.
Serial is just autoincrementing integer
There is no special command to get the value after insert you can use sql queries for it.
If you want to get value before insert then This article discusses about it I hope you get what you want

insert into t (iduser, iduser2) values (1,2)
returning idpms

I think you are looking for a KeyHolder object.
Assuming you are using Spring to perform database operations:
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.KeyHolder;
// stuff...
KeyHolder generatedKeyHolder = new GeneratedKeyHolder();
// Execute the update
namedJdbcTemplate.update(sqlQuery, params, generatedKeyHolder);
// Retrieve the map of ALL the autoincremented fields in the table
// Just get the desired one by field name
Integer idpms = (Integer) generatedKeyHolder.getKeys().get("idpms");
// use idbpms as parameter for your next query...
hope that helps

Related

How should my INSERT INTO statement for GENERATED BY DEFAULT AS IDENTITY be?

I'm trying to use GENERATED BY DEFAULT AS IDENTITY key for my record id's for my tables because a user needs to register themself and the user shouldn't be able to choose their own record id. So I decided to use GENERATED BY DEFAULT AS IDENTITY but I don't know how to write my INSERT statements.
This is my user table:
CREATE TABLE USER
(
ID_USER INT NOT NULL GENERATED BY DEFAULT AS IDENTITY,
USERNAME VARCHAR(20) UNIQUE NOT NULL,
FORENAME VARCHAR(20) NOT NULL,
SURNAME VARCHAR(20) NOT NULL,
PASSWORD VARCHAR(10) NOT NULL,
USER_TYPE INT NOT NULL,
PRIMARY KEY(ID_USER),
FOREIGN KEY (USER_TYPE) REFERENCES USER_TYPES(ID_TYPE)
);
and users will be allowed to register themselves.
This is what im using for my database
When a table has a column GENERATED BY DEFAULT AS IDENTITY it means that you can insert with a value in that column if you want to but you don't have to. So then in your insert, you could instead write
INSERT INTO ARTIST (ORIGIN,ARTIST_NAME) VALUES ('USA','Nirvana');
For reference: https://www.ibm.com/support/knowledgecenter/en/SSEPEK_11.0.0/apsg/src/tpc/db2z_identitycols.html
Edit after comment:
In the case where you need to retrieve the ID, #Mathias was correct that this is a duplicate question. A possible solution taken from this answer would be:
PreparedStatement result = cnx.prepareStatement(
"INSERT INTO ARTIST (ORIGIN,ARTIST_NAME) VALUES ('USA','Nirvana')",
RETURN_GENERATED_KEYS);
int updated = result.executeUpdate();
if (updated == 1) {
ResultSet generatedKeys = result.getGeneratedKeys();
if (generatedKeys.next()) {
int key = generatedKeys.getInt(1);
}
}
where key has the ID that you need for your next query.
The question is slightly different from the one already answered and needs a different answer.
The OP states: user shouldn't be able to choose their own record id. In that case the column definition should be ID_USER INT NOT NULL GENERATED ALWAYS AS IDENTITY to disallow any user-supplied value.
The table name shouldn't be USER as this is a reserved word. Try USERS instead.
The insert statement shouldn't insert into the ID_USER column. Similar to the example in the other answer, it should list the columns that are being inserted. An example below:
INSERT INTO USERS (USERNAME, FORENAME, SURNAME, PASSWORD, USER_TYPE)
VALUES ('JohnSmith','John', 'Smith', 'apasswrdx67', 3)
The OP wants to insert the generated value into another table using the GUI DatabaseManager. This is done by using the IDENTITY() function immediatly after inserting that row. For example,
INSERT INTO SOMETABLE (X, Y, Z) VALUES (IDENTITY(), 'some value', 'other value')

Bogus data in ResultSet

I'm having some issues with my ResultSet using JDBC.
Here's my relation:
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) not null,
lastname varchar(10) not null,
);
I'm trying to insert a (firstname, lastname) into the tuple and then get the person_id that comes out of it. Here's my JDBC code:
//connection is taken care of beforehand and is named con
prep = con.prepareStatement("insert into person (firstname, lastname) values (?, ?)", Statement.RETURN_GENERATED_KEYS);
prep.setString(1, firstname);
prep.setString(2, lastname);
prep.execute();
ResultSet generated = prep.getGeneratedKeys();
if (generated.next()) {
String key = generated.getString("0");
System.out.println(key);
}
This works all fine. But my problem is that the key should be an integer, not a String. Every time I run this, I get a ResultSet that contains a string of "AAA3vaAAGAAAFwbAAG", or something along those lines. I want to get the person_id so I can use it later in my Java program.
Is there something I'm doing wrong in regards to searching through the ResultSet or the execution of the statement itself?
tl;dr
int id = generated.getInt( 1 ) ;
Details
Your Question seems confused.
There are two forms of each get… method on ResultSet.
Pass a column number (an int)
Pass a column name (a String)
You seem to have combined the two into this:
String key = generated.getString( "0" ) ;
I doubt that you have a column named with a single digit zero. Besides being a poor choice of name, standard SQL forbids starting an identifier with a digit.
So that line makes no sense. Perhaps you meant the first column by using a zero 0 and mistakenly wrapped it in quotes, thereby transforming your intended int into an actual String.
Even that intention would be wrong. The ResultSet::getString documentation incorrectly describes the int as an “columnIndex”. Usually “index” means a zero-based counting offset. But actually ResultSet::getString( int ) requires you pass an ordinal number with counting starting at one. So getString( 0 ) is never valid.
So if you want to retrieve the value of your result set’s first column as text, do this:
String key = generated.getString( 1 ) ; // Retrieve first column of result set as text.
Yet again, this would be wrong in the context of your code. You are apparently attempting to retrieve the primary key values being generated during the INSERT. Your primary key column person_id is defined as number(5) which is not a textual type. So retrieving as a String is not appropriate.
NUMBER(5) is not standard SQL. If you happen to be using Oracle database, the doc says that would be an integer type with a precision of five, meaning numbers with up to five digits. So retrieve that as a integer type in Java by calling ResultSet::getInt.
int id = generated.getInt( 1 ) ; // Retrieve the new row’s ID from the first column of the result set of generated key values returned by the `INSERT` prepared statement.
My comments above are for databases in general. But for Oracle specifically, see the Answer by Mark Rotteveel explaining that Oracle database does not return the generated sequence number when calling getGeneratedKeys. Instead it returns ROWID pseudo-column.
Your problem is that Oracle by default returns the ROWID of the inserted record, and not the generated identifier. From Oracle JDBC Developer's Guide: Retrieval of Auto-Generated Keys:
If key columns are not explicitly indicated, then Oracle JDBC drivers
cannot identify which columns need to be retrieved. When a column name
or column index array is used, Oracle JDBC drivers can identify which
columns contain auto-generated keys that you want to retrieve.
However, when the Statement.RETURN_GENERATED_KEYS integer flag is
used, Oracle JDBC drivers cannot identify these columns. When the
integer flag is used to indicate that auto-generated keys are to be
returned, the ROWID pseudo column is returned as key. The ROWID
can be then fetched from the ResultSet object and can be used to
retrieve other columns.
So, if you use Statement.RETURN_GENERATED_KEYS, you'll get the ROWID, and you can then use that ROWID to select the inserted row to obtain the other values (including the generated identifier).
If you want to specifically retrieve the generated id, for Oracle you'll need to explicitly ask for that column as follows:
String[] columns = { "PERSON_ID" }
prep = con.prepareStatement(
"insert into person (firstname, lastname) values (?, ?)", columns);
prep.setString(1, firstname);
prep.setString(2, lastname);
prep.executeUpdate();
ResultSet generated = prep.getGeneratedKeys();
if (generated.next()) {
int key = generated.getInt("PERSON_ID");
System.out.println(key);
}

Insert into SQLite database if not exist in Java [duplicate]

I have an SQLite database. I am trying to insert values (users_id, lessoninfo_id) in table bookmarks, only if both do not exist before in a row.
INSERT INTO bookmarks(users_id,lessoninfo_id)
VALUES(
(SELECT _id FROM Users WHERE User='"+$('#user_lesson').html()+"'),
(SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+" AND cast(starttime AS int)="+Math.floor(result_set.rows.item(markerCount-1).starttime)+")
WHERE NOT EXISTS (
SELECT users_id,lessoninfo_id from bookmarks
WHERE users_id=(SELECT _id FROM Users
WHERE User='"+$('#user_lesson').html()+"') AND lessoninfo_id=(
SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+")))
This gives an error saying:
db error near where syntax.
If you never want to have duplicates, you should declare this as a table constraint:
CREATE TABLE bookmarks(
users_id INTEGER,
lessoninfo_id INTEGER,
UNIQUE(users_id, lessoninfo_id)
);
(A primary key over both columns would have the same effect.)
It is then possible to tell the database that you want to silently ignore records that would violate such a constraint:
INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)
If you have a table called memos that has two columns id and text you should be able to do like this:
INSERT INTO memos(id,text)
SELECT 5, 'text to insert'
WHERE NOT EXISTS(SELECT 1 FROM memos WHERE id = 5 AND text = 'text to insert');
If a record already contains a row where text is equal to 'text to insert' and id is equal to 5, then the insert operation will be ignored.
I don't know if this will work for your particular query, but perhaps it give you a hint on how to proceed.
I would advice that you instead design your table so that no duplicates are allowed as explained in #CLs answer below.
For a unique column, use this:
INSERT OR REPLACE INTO tableName (...) values(...);
For more information, see: sqlite.org/lang_insert
insert into bookmarks (users_id, lessoninfo_id)
select 1, 167
EXCEPT
select user_id, lessoninfo_id
from bookmarks
where user_id=1
and lessoninfo_id=167;
This is the fastest way.
For some other SQL engines, you can use a Dummy table containing 1 record.
e.g:
select 1, 167 from ONE_RECORD_DUMMY_TABLE

Retrieving Primary Key Generated By Trigger (Java)

Here's what I'm attempting to do. I have a Java program that decomms a telemetry stream into the individual raw fields. I am passing these raw fields values into a MySQL table where each column is one of the fields. In this database I also have a view that grabs all the telemetry data and calculates a few new derived columns based on raw data (e.g. raw counts to engineering units). In my Java program, after insertion I would like to grab the corresponding row from the VIEW (raw + derived) and pass that data along elsewhere.
Originally I thought I could simply insert the raw data into the VIEW and have the row returned to me in a ResultSet in the Java program. Unfortunately the data isn't returned in a ResultSet.
What I'm attempting to do now is insert the raw data into the table (this part works), get the primary key, then lookup the row from the VIEW. The part I'm struggling with is retrieving the primary key from the INSERT. I'm using a PreparedStatement generated from my Connection object and have supplied it with Statement.RETURN_GENERATED_KEYS. However, when I call getGeneratedKeys() on my statement after I call executeUpdate() my ResultSet is always empty. I can watch it insert the rows into the table while it's running...what am I doing wrong?
Can I not retrieve the generated primary key in this fashion if the primary key is generated via a trigger?
UPDATE: I've tried swapping out the Statement.RETURN_GENERATED_KEYS for a String array with the name of the primary key column, but that doesn't seem to work either.
I apologize for not including my code, but it would be difficult for me to do so. I've attempted to describe what I'm doing to the best of my abilities.
Ive seen this in another post. That claimed to work. Is this what yours looks like?
Statement stmt = db.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
numero = stmt.executeUpdate();
ResultSet rs = stmt.getGeneratedKeys();
if (rs.next()){
risultato=rs.getInt(1);
}
I have used SP's and here is an example of what I did. I used an in/out parm to get it back...
CREATE DEFINER=`scaha`#`localhost` PROCEDURE `updateprofile`(
IN in_idprofile INT(10),
IN in_usercode VARCHAR(50),
IN in_pwd VARCHAR(50),
IN in_nickname VARCHAR(50),
IN in_isactive tinyint,
IN in_updated timestamp,
OUT out_idprofile INT(10))
BEGIN
/* If the idprofile is < 1 then we insert a new record.. */
/* otherwise its an update */
if (in_idprofile < 1) then
insert into scaha.profile (usercode, pwd, nickname, isactive,updated) values (in_usercode,in_pwd,in_nickname,in_isactive,in_updated);
SET out_idprofile = LAST_INSERT_ID();
else
update scaha.profile set usercode = in_usercode, pwd = in_pwd, nickname = in_nickname, isactive = in_isactive, updated = in_updated
where idprofile = in_idprofile;
SET out_idprofile = in_idprofile;
end if;
END

How can I insert new values into two related tables?

I have a store program in java and a database made in access. I already have 2 tables in my database which are the customers table and the products table.
I want to add an orders table wherein it's primary key is an autonumber and an order_line table to complete this app. I want to have tables like this..
customer(cust_id, name, ....)
orders(order_no, cust_id, date_purchased,...)
order_line(order_no, product_id, ...)
products(product_id, product_name, price,....)
When the customer purchased the products, i could insert new values to the orders table. The thing that is not clear to me is how could i insert also in the order_line table, because the order_no I created in access is of type autonumber.
Would I make a select statement first to get the order_no value to put it to the order_no in order_line's table? Or I need to put this in one query only.
Anyone with experience to this? Any advice is appreciated.
The insertion into orders and order_line table should happen in a single transaction. While doing so, if you are using plain JDBC to insert record into orders table, you can register the order_no as an OUT parameter in your CallableStatement and get the value after the statement is executed and use to set the order_no attribute on the order_line records.
// begin transaction
connection.setAutoCommit(false);
CallableStatement cs = connection.prepareCall(INSERT_STMT_INTO_ORDERS_TABLE);
cs.registerOutParameter(1, Types.INT);
int updateCount = cs.execute();
// Check the update count.
long orderNo = cs.getInt(1);
// CallableStatement csLine for inserting into order_line table
// for (OrderLine line: orderLines) {
// Set the orderNo in line.
// set paramters on csLine.
// csLine.addBatch();
// }
// run the batch and verify update counts
connection.commit();
// connection.rollback() on error.
The JDBC-way (if you like database-independence), is to use the getGeneratedKeys() method of statement.
Use setAutoCommit(false), then execute the first query with the option Statement.RETURN_GENERATED_KEYS (eg for PreparedStatement).
Then use the getGeneratedKeys() method to retrieve the key (note: reference by column name, as the exact implementation and number of returned columns depends on the driver implementation.
And execute the second statement with that retrieved key.
Finally, commit().

Categories

Resources