How can I insert new values into two related tables? - java

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().

Related

Get a specific column of the updated rows

I need to know how to execute an update in JDBC with Oracle database backend and retrieve values for a specific column of the records that have been updated. The column that I am interested in is part of a composite primary key, e.g. COL_NAME in the example below.
I have tried the following:
String query = "UPDATE T1 SET COL_ABC = 'A'"; // Simplified
statement = conn.prepareStatement(query.toString(), new String[] { "COL_NAME" });
ResultSet rs = statement.getResultSet();
while (rs.next()) {
rs.getLong("COL_NAME");
}
But statement comes back as null.
I am not sure how to utilize RETURNING INTO in this case unless converting this whole thing into an anonymous PL/SQL block, if it is indeed a possible solution.
Please note that I need a list of the values from this column from all the records that have been updated.

Merge and When Matched query giving an error sql server

I have a query which I am trying to test. The query should update the data if it finds data in the table with existing primary key. If it doesn't then insert into the table.
The Primary key is of type int and in the properties I can see Identity is set to "True" which I assume it means that it will automatically set the new id for the primary if it is inserted.
MERGE INTO Test_table t
USING (SELECT 461232 ID,'Test1-data' Fascia FROM Test_table) s
ON (t.ID = s.ID)
WHEN MATCHED THEN
UPDATE SET t.Fascia = s.Fascia
WHEN NOT MATCHED THEN
INSERT (Fascia)
VALUES (s.Fascia);
The issue here is this query doesn't work and it never inserts the data or updates. Also, query gets compiled and I don't get any compilation error
Also the reason I want this query is to work because then I will use Java prepared statement to query the database so I am assuming I can do
SELECT ? ID,? Fascia FROM Test_table
So that I can pass the values with set methods in java.
Please let me know if there is something wrong in my query.
You are selecting from the target table as your source.
You either need to remove your FROM Test_table or have at least 1 row in Test_table prior to your merge.
rextester demo: http://rextester.com/XROJD28508
MERGE INTO Test_table t
USING (SELECT 461232 ID,'Test1-data' Fascia --FROM Test_table
) s
ON (t.ID = s.ID)
WHEN MATCHED THEN
UPDATE SET t.Fascia = s.Fascia
WHEN NOT MATCHED THEN
INSERT (Fascia)
VALUES (s.Fascia);

PostgreSQL unique string field

My database is PostgreSQL. The language is Java.
Table name is phrase with column name name.
At any time many users are inserting many rows to this table.
And we need to make sure that a certain field is unique.
And if such a field was found during loading, I want to return the row ID.
I could for example make a field the unique primary key, and when a row id inserted, catch the exception and look up the existing row.
But I think that is a bad idea.
I could just look for that row first and then insert.
But how can we avoid that the concurrent transactions get in each other's way?
And when downloading, is it better to do a batch download, and how do I do that in PostgreSQL? I do not even know.
You could create a UNIQUE constraint and INSERT ... ON CONFLICT:
CREATE TABLE mytable (
id integer PRIMARY KEY,
name text NOT NULL
CONSTRAINT name_unique UNIQUE
);
INSERT INTO mytable (id, name)
VALUES (1, 'me');
Now to run a batch INSERT that returns the id of each affecte row, run
INSERT INTO mytable (id, name)
VALUES (2, 'me'),
(3, 'new')
ON CONFLICT (name)
DO UPDATE SET name = EXCLUDED.name
RETURNING id;
The strange UPDATE that does not actually change the row is necessary if you want the id back.
Instead of catching the exception, you can use the INSERT ... ON CONFLICT DO NOTHING clause available in PostgreSQL. By checking the number of affected rows (returncode of PreparedStatement.executeUpdate), you can detect if there was a conflict.
E.g.
PreparedStatement pstmt = conn.prepareStatement("insert into x values (?,?) on conflict do nothing");
pstmt.setInt(1, myId);
pstmt.setInt(2, myValue);
int rc = pstmt.executeUpdate();
if (rc == 0) {
// fetch the existing row...
}

How to insert data into two table which has PK , FK relation in MS-Access using JDBC

I have two table Order1 (OrderNO is PK in Order1)and order2 (OrderNO is FK in order2 ) in MS Access , i have to insert data in this two table using JDBC. so please can any one tell me the sol. i try it but data is inserting in only 1 st table and gives error INSERT INTO is wrong
You can use batch update facility of JDBC 2.0 in order to insert into multiple tables as a batch or as a single unit. In this case your application will hit underlying database(MS access in your case) only once so performance will be increased as compared to one by one insertion.
You can add below given code in your own..
or simply can get idea that how to implement.
Statement stmt = con.createStatement();
con.setAutoCommit(false);
stmt.addBatch("INSERT INTO Order1 VALUES (OrderNO , ..., ...)");
stmt.addBatch("INSERT INTO Order2 VALUES (OrderNO , ...)");
int [] updateCounts = stmt.executeBatch();
Here AutoCommit() is set to false so it will free your application to decide whether to commit or not if any one of command in batch fails to execute or in case of any other error.

Return Timestamp With Prepared Statement

I have an auto generated timestamp that is created each time a record is inserted or updated in a mysql table. Is there a way to return this timestamp in a way similar to how I would use a keyholder to return a newly created id?
KeyHolder keyHolder = new GeneratedKeyHolder();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//Insert Contact
jdbcTemplate.update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement preparedStatement = connection.prepareStatement(SQL_ADD, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, contact.getFirstName());
preparedStatement.setString(2, contact.getLastName());
preparedStatement.setInt(3, contact.getOrganizationId());
preparedStatement.setString(4, contact.getType());
preparedStatement.setInt(5, contact.getUserId());
return preparedStatement;
}
}, keyHolder);
//Use keyholder to obtain newly created id
contact.setId(keyHolder.getKey().intValue());
Is there some way to also return the new timestamp without having to requery the table? I have been looking for ways to return it along with the id as a key in the keyholder, but it doesn't seem to be returned as a key?
Not very satisfying, but I think "no" is the answer to your question. I don't know any of the Spring stuff, but I think this is due to the basic JDBC that it's wrapping. See http://docs.oracle.com/javase/6/docs/api/java/sql/Statement.html#getGeneratedKeys%28%29
You only option would be to create a stored procedure on MySQL that has an out parameter and call that. See http://dev.mysql.com/doc/refman/5.0/en/call.html.
There are few options for solving this issue on the MySQL database server side. You could start with creating a TRIGGER on the table. As TRIGGER has a restriction and cannot return data, you can set the TIMESTAMP value to a variable:
DEMILITER //
CREATE TRIGGER ai_tbl_name AFTER INSERT ON tbl_name
FOR EACH ROW
BEGIN
SET #TimeStamp = NEW.timestamp_column;
END;//
DELIMITER ;
To retrieve this timestamp value, run the following command:
SELECT #TimeStamp;
Since the variables are stored in the memory, there will be no need to open any tables again.
You go even further. You could create a STORED PROCEDURE in MySQL to automate all the above (sample code, as I do not know your table's details):
DELIMITER //
DROP PROCEDURE IF EXISTS sp_procedure_name //
CREATE PROCEDURE sp_procedure_name (IN col1_val VARCHAR(25),
IN col2_val VARCHAR(25),
IN col3_val INT)
BEGIN
INSERT INTO tbl_name (col1, col2, col3)
VALUES (col1_val, col2_val, col3_val);
SELECT #TimeStamp;
END; //
DELIMITER ;
You can run this procedure with the following code:
CALL sp_procedure_name(col1_val, col2_val, col3_val);
As I'm not familiar with the Java, you'll need to finish it up with your side of code.
It seems that the variable contact is an instance for the newly inserted record. As it contains the newly generated id (primary key) field value, you can execute a new query to return the required timestamp field value for this new id.
The query may look like this:
select timestamp_field from my_table where id=?
Use PreparedStatement to input new id value and execute it to fetch required timestamp field value.
GeneratedKeyHolder also has two methods: getKeyList() that returns Map<String,Object> of generated fields; and getKeyList() that produces a list of generated keys for all affected rows.
See java doc of GeneratedKeyHolder and Spring tutorial of auto generated keys
In addition Spring's SimpleJdbcInsert has methods for generated key retrieval. See also method SimpleJdbcInsert#usingGeneratedKeyColumns
There are 2 methods in java.sql.Connection class causing PreparedStatement execution to return selected key columns :
PreparedStatement prepareStatement(String sql,
int[] columnIndexes)
throws SQLException
PreparedStatement prepareStatement(String sql,
String[] columnNames)
throws SQLException
You don't need to use Spring KeyHolder & JDBCTemplate to do this.
The give hope you could number/name your timestamp column. But the javadoc doesn't require or suggest that any JDBC implementation can return non-key columns, so your out of luck with this approach:
Creates a default PreparedStatement object capable of returning the auto-generated keys
designated by the given array. This array contains the names of the columns in the target
table that contain the auto-generated keys that should be returned.
As suggested in another answer, can switch to a stored procedure that does exactly what you want (CallableStatement is actually a PreparedStatement that executes storedprocedures - i.e. a subclass).
Can populate the timestamp column within the prepared statement via new Timestamp(new Date()) - but you should have in place a mechanism to sync times across your various servers (which is often used in windows and *nix environments). Your trigger could set the timestamp only if a value wasn't already provided.
As part of your app & DB design, you need to commit to a philosophy of where certain operations occur. If the DB derives needed data, the app needs to refresh data - you must pay the price of separate query executions or a combined stored proc that inserts & retrieves.

Categories

Resources