In my code base, we have a MyBatis query like below,
INSERT INTO TABLE_A(
ID,
NAME,
VERSION
)
VALUES (
#id#,
#name#,
(select NVL(max(version), 0 ) + 1 from SAE_PROC_SETTING where name = #name#)
)
The unique constraint is on columns name and version. If multiple users are inserting values at same time, sometimes we are getting unique constraint error. When we checked, the name and version is coming as same and throwing the error as expected.
My question is, how MyBatis handles the inner query
(select NVL(max(version), 0 ) + 1 from TABLE_Awhere name = #name#)
Does this query is submitted by MyBatis to Oracle and then oracle first executes the SELECT and then INSERT query OR Does MyBatis executes the SELECT first, then substitute the value in INSERT and submits the INSERT query in Oracle (2 steps by MyBatis) ?
If it's handled like second option, when 2 people are inserting with same name at same TIME, there is a probability that both got the same version. Then when trying to insert, we will get UniqueConstraint error.
Please let me know how MyBatis handles this internally. Any pointers are fine.
Thanks,
SD
MyBatis sends the full statement (insert with inner select) to JDBC driver and is the database (in your case Oracle) which does this operation (first executes the SELECT and then INSERT). MyBatis just replaces your query params and then passes the query by a prepareStatement.
The log show the insert as one statement.
2016-07-26 17:34:23.776 DEBUG 91036 --- [ main] sample.mybatis.mapper.CityMapper.insert : ==> Preparing: insert into city (name, state, country) values ((select DISTINCT 'a' from city), 'CA', 'US');
2016-07-26 17:34:23.777 DEBUG 91036 --- [ main] sample.mybatis.mapper.CityMapper.insert : ==> Parameters:
2016-07-26 17:34:23.779 DEBUG 91036 --- [ main] sample.mybatis.mapper.CityMapper.insert : <== Updates: 1
Then I debug it and when It is called this method (source github) just pass for INSERT case:
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
.....
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
....
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
....
}
Related
PostgreSQL Query
select date,count(*) from table1
where (DATE_PART('day', current_date::timestamp - table1.date::timestamp ))
<(SELECT value from keyvaluepair where priority='Important')
and priority = 'Important' group by date
order by date
I will be calling from api where
http://localhost:8080/get/getDates?priority=Important
I will be passing as ? in both places as shown
select date,count(*) from table1
where (DATE_PART('day', current_date::timestamp - table1.date::timestamp))
<(SELECT value from keyvaluepair where priority=?)
and priority = ? group by date
order by date
I'm getting error like this
No value specified for parameter 2.; nested exception is org.postgresql.util.PSQLException: No value specified for parameter 2.
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback;
In java I'm just getting this query data date and count.
public Map<String,Object> getDates(String priority) {
Map<String,Object> map = new Map<String,Object>();
List<Object> count = new ArrayList<Object>();
List<Object> date = new ArrayList<Object>();
try {
jdbcTemplate.query(query, new Object[] { priority }, new RowMapper<Object>() {
#Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
date.add(rs.getString("date"));
count.add(rs.getInt("count"));
return null;
}
});
} catch (DataAccessException e) {
e.printStackTrace();
}
return map;
}
How to give priority once and use it twice in query?
select t1.date,count(*) from table1 t1
where (DATE_PART('day', current_date::timestamp - t1.date::timestamp ))
<(SELECT value from keyvaluepair k where k.priority=t1.priority)
and t1.priority = 'Important' group by t1.date
order by t1.date
This changes in query helped me in resolving error which I had as shown
No value specified for parameter 2.; nested exception is org.postgresql.util.PSQLException: No value specified for parameter 2.
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback;
where two column names of table are same and I have to pass value once for all parameters as in link show below
http://localhost:8080/get/getDates?priority=Important
select t1.date,count(*) from table1 t1
where (DATE_PART('day', current_date::timestamp - t1.date::timestamp ))
<(SELECT value from keyvaluepair k where k.priority=t1.priority)
and t1.priority = ? group by t1.date
order by t1.date
here in this link single value that is priority Important is taken to query where it is used for both tables parameter of same column name.
I have following query which select from employee table where name is "max" and ID not in 123 and 444.
Not in IDs can grow in future. But I am receiving error as
Error
( 8023): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: DatabaseException(near "?": syntax error (code 1 SQLITE_ERROR): , while compiling:
Query
List<String> a = [];
a.add("123");
a.add("444");
var table = await mydb.rawQuery(
"SELECT value from employee WHERE employeename = ? AND id NOT IN ? ORDER BY timestamp DESC",
["max", a]);
If the LIST is unpredictable, one way is that you can use JOIN to create your select statement with required value of NOT IN. Below is one sample.
void main() {
List<String> a = [];
a.add("123");
a.add("444");
var select =
'SELECT value from employee WHERE employeename = ? AND id NOT IN (\'' +
(a.join('\',\'')).toString() +
'\') ORDER BY timestamp DESC';
var table = await mydb.rawQuery(select, ["max"]);
}
If you print the variable select you will get
SELECT value from employee WHERE employeename = ? AND id NOT IN ('123','444')
ORDER BY timestamp DESC.
Then you can pass the above statement to rawquery and get your result.
P.S:Use your single quote and double quote accordingly.
I'd go for #arun-palanisamy 's solution, see his comment. Props go to him. I just tried the following -- with Groovy/Postgres, but the error seems to be the same, so you might want to give it a try:
String[] a = ['123', '444']
// your code, throws 'ERROR: syntax error at or near "$2"':
// def table = sql.execute("SELECT value from employee WHERE employeename = ? AND id NOT IN ? ORDER BY timestamp DESC", ["max", a])
// code of arun-palanisamy, compiles:
def table = sql.execute("SELECT value from employee WHERE employeename = ? AND id NOT IN (${a.join(', ')}) ORDER BY timestamp DESC", ["max", a])
Side notes:
You might want to try a different type for a, such as Array in my code, or even a HashMap.
There are examples (like here) where the number of ? are generated dynamically.
Update: Go for this answer, we posted simultaneously
I would like to do a check in my PostgreSQL database with Eclipse Link in a named query and return a boolean. However when I change my count statement (which returns a correct value) to a case statement I get a NoResultException. What is the problem?
Following a simplified example:
#NamedQuery(name = "User.isExistent",
query = "SELECT CASE WHEN COUNT(u) > 0 THEN true ELSE false END
FROM User u WHERE u.someField = :someField")
Usage
TypedQuery<Boolean> query = em.createNamedQuery("User.isExistent", Boolean.class);
query.setParameter("someField", "someFieldValue");
Boolean result = query.getSingleResult();
hey i'm looking for way to search for text pattern (in jpa) and to sort the result, first all the result starting with this string and then all other result.
i have found Mysql order by using search string to get the answer for mysql
most of the answers use union(which does not exist in jpa) and force to query the db or open a view for that. (ordering from code is not that good solution since we use paging to get part of the result as the result size can be really big)
One solution i like from the link above is :
select * from employee where name like '%ani%' order by locate('ani', name) asc, name asc
source
This seems to me very clear but i'm not sure how to convert it to jpa. seems like Order object is not able to get locate output
any ideas will be welcome
Thanks!
Alon
EDIT:
thanks for reply. i'm tring to achive the same with jpa critiera
Iterator<Order> sortingIter = page.getSort().iterator();
ArrayList<javax.persistence.criteria.Order> order = new ArrayList<javax.persistence.criteria.Order>();
String fieldName;
while (sortingIter.hasNext()) {
Order sort = sortingIter.next();
fieldName = sort.getProperty();
order.add(sort.getDirection() == Sort.Direction.ASC ? cb
.asc(keyword.get(fieldName)) : cb.desc(keyword
.get(fieldName)));
}
while the above works well. i cannot add the following line to the code. seems like Order object doesnt like them
Expression<String> fieldValue = keyword.get(fieldName);
order.add(cb.locate(fieldValue,key));
EDIT 2:
tried
order.add(new javax.persistence.criteria.Order() {
#Override
public javax.persistence.criteria.Order reverse() {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean isAscending() {
// TODO Auto-generated method stub
return true;
}
#Override
public Expression<?> getExpression() {
// TODO Auto-generated method stub
return cb.locate(fieldValue,key);
}
});
jpa doesn't complain but the query does not get the right order
EDIT 3:
Found my mistake!
The key value i was passing above already contained "%" and both sides... so locate did not work properly.
now i'm getting some weird behavior on some special chars:if - for example - i have the word Ghurabā the query like %ba% will find it. but, it seems that locate(Ghurabā,ba) will return 0 - meaning as pattern was not found in string any idea how to overcome this issue?
seems like this is not only jpa but also mysql behavior.
SELECT *
FROM `keywords`
WHERE name LIKE '%ba%'
ORDER BY LOCATE( 'ba', name ) , name
LIMIT 0 , 30
will return the next result
Ghurabā'
Khuṭabā'
qabā\
Ribāṭ
ba'urchi (cook)
Baghdad
...
note that it does work for "regular english characters" but there is a mismatch between the like and the locate function
Using Collcation: utf8_general_ci (got the same result with utf_unicode_ci)
This does not makes any complain.
String jpql = "select e from Employee e where e.name like '%ani%' order by locate('ani', e.name) asc, e.name asc";
TypedQuery<Employee> query2 = em.createQuery(jpql ,Employee.class);
And this is the translation that hibernate does.
Hibernate: select employee0_.id as id1_2_, employee0_.address_id as
address5_2_, employee0_.DEPT_ID as DEPT6_2_, employee0_.manager_id as
manager7_2_, employee0_.name as name2_2_, employee0_.salary as
salary3_2_, employee0_.startDate as startDat4_2_ from Employee
employee0_ where employee0_.name like '%ani%' order by locate('ani',
employee0_.name) asc, employee0_.name asc
Using some data as the link you mention.
Employee 10: name: anil, salary: 59000,
Employee 1: name: anirudha, salary: 55000,
Employee 5: name: rani,
Employee 7: name: Stephanie, salary: 54000,
{anil,anirudha,rani, ...}
Same problem using CriteriQuery solution
Ok, you own me some points for this =)
Hibernate: select employee0_.id as id1_2_, employee0_.address_id as address5_2_, employee0_.DEPT_ID as DEPT6_2_, employee0_.manager_id as manager7_2_, employee0_.name as name2_2_, employee0_.salary as salary3_2_, employee0_.startDate as startDat4_2_ from Employee employee0_ where employee0_.name like ? order by locate(?, employee0_.name) asc, employee0_.name asc
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> root = cq.from(Employee.class);
cq.where(cb.like(root.<String>get("name"), "%ani%"));
cq.orderBy(cb.asc(cb.locate(root.<String>get("name"), "ani")), cb.asc(root.get("name")));
TypedQuery<Employee> query2 = em.createQuery(cq);
printList(query2.getResultList());
Try the above it should work.
Employee 10: name: anil, salary: 59000,
Employee 1: name: anirudha, salary: 55000,
Employee 5: name: rani,
Employee 7: name: Stephanie, salary: 54000,
Check this out if you think ?(question mark) is not correct in the query.
http://webdev.apl.jhu.edu/~jcs/ejava-javaee/coursedocs/605-784-site/docs/content/html/jpa-query-criteria-function.html#jpa-query-criteria-function-string-locate
I'm trying to execute SELECT statement, where parameters might have null values:
SQL(
"""
SELECT id FROM devices WHERE
name = {name}
""")
.on("name" -> device.name)()
.collectFirst {
...
}.getOrElse {
...
}
device.name can return null. With db.default.logStatements=true I see that generated SQL looks like this: SELECT id FROM devices WHERE name = NULL.
name = NULL is not quite valid for Postgre SQL, but I've enabled it using transform_null_equals. Now when I execute SQL from log using pgAdmin, it works perfectly fine. However, ANORM does not find anything.
Following code does return result:
SQL(
"""
SELECT id FROM devices WHERE
name = NULL
""")
.on("name" -> device.name)()
.collectFirst {
...
}.getOrElse {
...
}
What's wrong with it?!