Add Envers revision to an existing and Not Audited table - java

I have a table, populated with an import file.
Now I need to declare the related entity AUDIT and We have try to create a procedure for insert the revinfo in the Audit Table, by this way:
Extract from the DB the max REV and max RevTS
#Query(value="select max(rev) from revinfo",nativeQuery=true)
int findMaxRev();
#Query(value="select max(revtstmp) from revinfo",nativeQuery=true)
Long findMaxrevtstmp();
At this data we add a +1 value, and try to set it in this query:
#Query(value="insert into revinfo (`rev`, `revtstmp`) values (:rev, :revtstmp)", nativeQuery=true)
void addRevInfo(#Param("rev") int rev, #Param("revtstmp")Long revtstmp);
#Query(value="insert into entity_h (id, audit_revision, action_type, audit_revision_end, audit_revision_end_ts ) "
+ "values (:id, :rev, 0, null, '2017-08-31 10:45:37')", nativeQuery=true)
void addEnvers(#Param("id")long id, #Param("rev")int rev);
But when we run the addRevInfo query, We obtain this error:
`ERROR: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Can not issue data manipulation statements with executeQuery()`.
If we run this same query directly in MySQLWorkbench, the insert run without problem.
What's wrong?

Try to add this to you insert query:
#Modifying(clearAutomatically = true)
#Query("....")
With that the EntityManager flush your changes otherwise not, and it permit to use the executeUpdate() instead of exectueQuery() works for
the SQL statement, which returns a single ResultSet object
The executeUpdate instead is
for SQL statement, which may be an INSERT, UPDATE, or DELETE statement
or an SQL statement that returns nothing, such as an SQL DDL
statement.

Related

Return array of deleted elements postgresql JDBC

This is my database:
dragons
id, key, name, age, creation_date
users
id, name, user, pass
users_dragons
user_id, dragon_id
So this is my code for deleting dragons from the database that have a bigger key that the passed and belongs to a determination user. The SQL query works perfectly for deleting them but not for returning the array of keys from the deleted elements.
I tried using PreparedStatement but later I checked, as far as I know, that this class doesn't return arrays, and the CallableStatement is only for executing processes in the db, and I don't know how they return arrays.
String query = "" +
"DELETE FROM dragons " +
"WHERE id IN (SELECT d.id FROM dragons d, users u, users_dragons ud" +
" WHERE d.key > ?" +
" AND ud.dragon_id = d.iD" +
" AND ud.user_id in (select id from users where id = ?)) RETURNING key INTO ?";
CallableStatement callableStatement = connection.prepareCall(query);
int pointer = 0;
callableStatement.setInt(++pointer, key);
callableStatement.setInt(++pointer, credentials.id);
callableStatement.registerOutParameter(++pointer, Types.INTEGER);
callableStatement.executeUpdate();
return (int []) callableStatement.getArray(1).getArray();
The code is giving me the error, but is obvious because the CallableStatement needs a postgres function to run and not a simple SQL query
org.postgresql.util.PSQLException: This statement does not declare an OUT parameter.
Use { ?= call ... } to declare one.
at org.postgresql.jdbc.PgCallableStatement.registerOutParameter
.......
It would be really helpful how would be the correct JDBC algorithm to delete the elements from the database and return the array of keys of the deleted items.
You treat such a statement like a normal SELECT statement: use java.sql.PreparedStatement.executeQuery() or java.sql.Statement.executeQuery(String sql) to execute the statement and get a result set.
java.sql.CallableStatement is for calling Procedures (but you don't need it in PostgreSQL).

Sqlite-JDBC update with LIMIT clause?

I am trying to use the update query with the LIMIT clause using sqlite-JDBC.
Let's say there are 100 bob's in the table but I only want to update one of the records.
Sample code:
String name1 = "bob";
String name2 = "alice";
String updateSql = "update mytable set user = :name1 " +
"where user is :name2 " +
"limit 1";
try (Connection con = sql2o.open()) {
con.createQuery(updateSql)
.addParameter("bob", name1)
.addParameter("alice", name2)
.executeUpdate();
} catch(Exception e) {
e.printStackTrace();
}
I get an error:
org.sql2o.Sql2oException: Error preparing statement - [SQLITE_ERROR] SQL error or missing database (near "limit": syntax error)
Using
sqlite-jdbc 3.31
sql2o 1.6 (easy database query library)
The flag:
SQLITE_ENABLE_UPDATE_DELETE_LIMIT
needs to be set to get the limit clause to work with the update query.
I know the SELECT method works with the LIMIT clause but I would need 2 queries to do this task; SELECT then UPDATE.
If there is no way to get LIMIT to work with UPDATE then I will just use the slightly more messy method of having a query and sub query to get things to work.
Maybe there is a way to get sqlite-JDBC to use an external sqlite engine outside of the integrated one, which has been compiled with the flag set.
Any help appreciated.
You can try this query instead:
UPDATE mytable SET user = :name1
WHERE ROWID = (SELECT MIN(ROWID)
FROM mytable
WHERE user = :name2);
ROWID is a special column available in all tables (unless you use WITHOUT ROWID)

Informix java.sql.SQLException: Column (...) not found in any table in the query (or SLV is undefined)

The query below is working without any problems in my java based sql Editor:
begin work;
create SEQUENCE if not exists zahlpaketcounter start 1;
select zahlpaketcounter.nextval as counter,*
from (
SELECT
firma_nr
,zahlpaket.nummer
,zahlpaket.bezeichnung
,personenkonto.kontonummer
,personenkonto.bezeichnung
,zahlbewegung.op_nr
,zahlbewegung.zahlbetrag_druck
,fibu_beleg.archiv_nr
FROM integris.zahlbewegung
join zahlpaket on zahlbewegung.zahlpaket_id=zahlpaket.zahlpaket_id
join integris.personenkonto on zahlbewegung.personenkonto_id=personenkonto.personenkonto_id
join integris.opbewegung on zahlbewegung.opbewegung_id=opbewegung.opbewegung_id
join integris.fibu_beleg on opbewegung.fibu_beleg_id=fibu_beleg.fibu_beleg_id
join integris.firma on zahlpaket.firma_id = firma.firma_id
where 1=1
and zahlbewegung.zahlbetrag_druck >=0
order by nummer,personenkonto.kontonummer,zahlbewegung.op_nr
);
drop sequence zahlpaketcounter;
commit work;
when I use in it java:
sql=getTextResource(this,"sql/getZahlläufe.sql");
fibustmt.execute(sql);
the execute method fails with:
java.sql.SQLException: Column (zahlpaketcounter) not found in any table in the query (or SLV is undefined).
Why? Any Ideas?
Seems not possible to use multiple statements with execute(). You should use addBatch() and executeBatch() but not with a SELECT.
It works with 3 execute().
String sqlQ="create SEQUENCE if not exists zahlpaketcounter start 1";
PreparedStatement pstmt = cnx.prepareStatement();
pstmt.execute();
sqlQ="SELECT ...";
pstmt = cnx.prepareStatement();
pstmt.execute();
sqlQ="drop SEQUENCE if exists zahlpaketcounter";
pstmt = cnx.prepareStatement();
pstmt.execute();

Spring MVC JPA Native Insert With Generated Column Returned

These are the things I need to accomplish when inserting into PostgreSQL via JPA.
1) Insert to a table with the following added to the end of the insert "ON CONFLICT DO NOTHING" (Or some annotation if that exists)
2) Have the generated id column returned
Currently I am using the following method but it does not return the generated column...
#Transactional
#Modifying
#Query(nativeQuery = true, value = "INSERT INTO table_name (value1) values(?1) ON CONFLICT DO NOTHING")
int insertWithoutConflict(Long value1);
The solution I have that works without JPA involved is the following....
try(Connection conn = DatabaseUtils.getConnection()) {
Statement statement = conn.createStatement();
statement.execute(query, Statement.RETURN_GENERATED_KEYS);
ResultSet resultSet = statement.getGeneratedKeys();
if (resultSet.next())
return resultSet.getLong(1);
}
Only problem with this is that I then am circumventing our current process and then have to start implementing a connection pool and I do not want to get into that. I want to know if this solution is possible in JPA or Hibernate.
Answer according to #Kayaman
#Transactional
#Query(nativeQuery = true, value = "INSERT INTO My_Table(value_1, value_2) values(?1, ?2) RETURNING any_column")
Long insertWithoutConflict(String value1, Long value2);
Can also return the model object I believe
#Transactional
#Query(nativeQuery = true, value = "INSERT INTO My_Table(value_1, value_2) values(?1, ?2) RETURNING column_1, columnName_2, columnName_3, columnName_4")
YourModelObject insertWithoutConflict(String value1, Long value2);
Remove the #Modifying annotation, since it the query may not modify the data.
Then add ON CONFLICT DO NOTHING RETURNING value1 (or RETURNING *), but you'll have to change that int to Integer since a conflict won't return any generated values.

Deciding addition or updation

I need to add a record if already a record with the primary key doesn't exist; otherwise existing record is to be updated. For this I am querying the db with the primary key. If no record exist, I am adding; otherwise updating. I am coding this in java using raw JDBC.
Is there a better way to do this?
insert … select … where not exist
INSERT INTO ... VALUES ... ON duplicate KEY UPDATE id = id
REPLACE INTO ... SELECT ... FROM ...
The most soft way to do this is to use special query INSERT ... ON DUPLICATE KEY UPDATE query in My Sql. It is much more effective than check is conflict exist on the application side.
Code snippet for example:
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(
"INSERT INTO table (a,b,c) VALUES (?,?,?) ON DUPLICATE KEY UPDATE c=?;"
);
int paramIndex = 1;
statement.setInt(parameterIndex++, primaryKeyValue);
statement.setInt(parameterIndex++, secondValue);
statement.setInt(parameterIndex++, thirdValue);
statement.setInt(parameterIndex++, thirdValue);
int updatedCount = statement.executeUpdate();
} finally {
statement.close();
}
Another way would be REPLACE INTO which takes the same syntax as INSERT but removes the old entry when the primary key already exists before inserting.
The simplest and the most general way is to count the record before insert/update.
Pseudo Code:
SELECT COUNT(*) as recordCount FROM mytable WHERE keyField = ?
if (recordCount > 0) {
UPDATE mytable SET value1=? WHERE keyField = ?
} else {
INSERT INTO mytable (keyField, value1) VALUES (?, ?)
}

Categories

Resources