Calculating age from birthdate with #Formula - java

I'm trying to calculate the user's age from her birthdate, using #Formula.
According MySQL documentation, I have tried this:
#Entity
#Table(name = "users")
public final class UserProfile {
//this column is called BIRTHDATE in database
private String birthdate;
#Formula("(select TIMESTAMPDIFF(YEAR,BIRTHDATE,CURDATE()) from users)")
private String age;
//more things...
}
But I get an error:
java.sql.SQLSyntaxErrorException: You have an error in your SQL
syntax; check the manual that corresponds to your MariaDB server
version for the right syntax to use near
'userprofil0_.YEAR,userprofil0_.BIRTHDATE,CURDATE()) from users) as
formula0_0_ f' at line 1
If I execute that query in phpMyAdmin, it works properly.
Following this, I have also tried with:
#Formula("date_part('year', age(birthdate))")
private String age; //I tried with int instead of String, too
But I have this error:
java.sql.SQLSyntaxErrorException: FUNCTION
userprofile-service-db.date_part does not exist
This one does not work even in phpMyAdmin...
Any idea?
EDIT
I have just tried with:
#Formula("(TIMESTAMPDIFF(YEAR,BIRTHDATE,CURDATE()))")
private String age;
but is still not working. This is the query that Hibernate shows:
select
userprofil0_.id as id1_1_0_,
userprofil0_.about_me as about_me2_1_0_,
userprofil0_.birthdate as birthdat3_1_0_,
userprofil0_.display_name as display_4_1_0_,
userprofil0_.email as email5_1_0_,
userprofil0_.profile_photo as profile_6_1_0_,
(TIMESTAMPDIFF(userprofil0_.YEAR,
userprofil0_.BIRTHDATE,
CURDATE())) as formula0_0_
from
users userprofil0_
where
userprofil0_.id=?
It looks like Hibernate is taking YEAR as a column, but actually it is a reserved word. If I execute that query in phpMyAdmin replacing userprofil0_.YEAR with just YEAR, it works fine.

Your first attempt was almost right, but you don't need select and from parts since column BITHDATE is in the same table:
#Formula("(TIMESTAMPDIFF(YEAR,BIRTHDATE,CURDATE()))")
private String age;
Also would be useful to turn on the logging of generated SQL query (in Hibernate it's done by setting property show_sql to true), to see the whole query.
UPDATE
As a workaround of the treating YEAR as a column name by Hibernate you can wrap call to TIMESTAMPDIFF in a custom MySQL function and call this function in Formula. Here is the SO answer to a similar problem.
Another solution could be to write a custom dialect resolver, which will treat YEAR as a keyword: SO answer

Try this formula to calculate the difference between current date and BIRTHDATE column stored in the database to get user age in year
#Formula("YEAR(CURDATE()) - YEAR(BIRTHDATE)")
private int age;

Related

Hibernate: Value too long for column

For a project I am working on, we use Spring Boot JPA with H2 database to store certain objects and information. However, after testing the application a bit, I got the following error:
2022-04-03 17:41:19 jdbc[3]: exception
org.h2.jdbc.JdbcSQLDataException: Value too long for column "LIST_OF_PLAYERS VARBINARY(255)": "X'aced0005737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a6578700000000a77040000000a7372000e6a61... (262)"; SQL statement:
update lobby set host_id=?, is_public=?, is_started=?, list_of_players=?, token=? where id=? [22001-200]
So I figured that I had to change the maximum allowed number of characters and did the following:
#Column(name = "listOfPlayers", length = 10000)
public ArrayList<Long> playerIds;
It appears that the length attribute only works for VARCHAR and not for VARBINARY. Is it possible to set the maximum for VARBINARY too? If so how?

Spring jpa check if record exist using String date

I would like to check the DB if a record already exists for a give run date and name using Spring JPA query using two params:
#Query("SELECT CASE WHEN COUNT(r)> 0 THEN true ELSE false END FROM REQUEST r WHERE r.NAME = :reqName AND r.RUN_DATE = :runDate")
boolean existsRequest(#Param("reqName") String reqName,
#Param("runDate") String runDate);
The type of RUN_DATE in Database H2, Sql Server is a DATE field. Yet I am providing String as param for the date in format YYYY-MM-DD.
The above doesn't work for me and I was wondering how to write it correctly using both JPQL and nativeQuery ?
For this specific case, I think the most elegant way is to use query method:
boolean existsByNameAndRunDate(String name, String runDate);

Mysql Date Column Error during insertion from Java

I want to insert a data using JDBC, whenever I execute the program then it shows me some Mysql error:
Insert statement:
String sql = "INSERT into books(name, isbn, author, category, desc, published) VALUES('"+name+"','"+isbn+"','"+author+"','"+category+"', '"+desc+"','"+book_published+"')";
I am trying to convert the string to date here using :
String yr = year.getSelectedItem().toString();
String mn = month.getSelectedItem().toString();
String dy = day.getSelectedItem().toString();
String book_date = yr+"-"+mn+"-"+dy;
DateFormat df = new SimpleDateFormat("yyyy-MM-dd",
Locale.ENGLISH);
try{
Date book_published = df.parse(book_date);
}catch(...){...}
and it shows me error like :
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'desc, published) VALUES('skd flakj','klsdjf askj','kl jasdklfj kl','kls djfklj f' at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
Please help me figure out what is the problem here.
Your code is prone to SQL injection attacks due to use of normal query statements. To secure your query use preparedstatement.
As per your query issue, DESC is a reserved word. So you can't use it as column name.View this for complete list of reserved words.
desc is a reserved word for MySQL, which means u can just use it plainly.
To use it without getting an error from MySQL, u should use ` surround the reserved word.
Ps: u SQL statement may suffer from SQL injection if using user-inputed parameters, attackers can use it to get control of ur system.Maybe u should try to hv a look on this one.
https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
desc is not a particularly good column name because it's a reserved word in MySQL. I'm not sure if this is the only issue here but you may want to try surrounding desc with ticks, like so:
String sql = "INSERT into books(`name`, `isbn`, `author`, `category`, `desc`, `published`) VALUES('"+name+"','"+isbn+"','"+author+"','"+category+"', '"+desc+"','"+book_published+"')";
It's good practice anyway.
Edit: and as others have mentioned, prepared statements are safer when saving untrusted input to a database.

Intellij IDEA jpa console issue select from tables with specific columns

We have a project includes Eclipselink and MySQL.
For example if we use simple query:
SELECT a from ExampleTable a
it is transformed to something like this:
SELECT `id`, `code`, `high`, `key`, `name`, `regionalCode` FROM `ExampleTable`
and if I am using JPA Console I am getting something like that:
SELECT id, code, high, key, name, regionalCode FROM ExampleTable
and error message
[42000][1064] You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key, name, regionalCode FROM ExampleTable' at line 1
The problem is "key" column but I have no chance to rename it.
I tried to find options to fix that but have no results.
I think if there will be no answer - the good way is to create bug report.
How we get enclosed names of columns?
We are using EntityManager
EntityManager em;
...
TypedQuery = em.createQuery("SELECT et FROM ExampleTable et");
And if we run it we see (in debug mode) that all names in generated query are enclosed with ` symbol.
key is reserved keyword of MySQL database (see MySQL: Reserved Words).
so you should escape reserved keyword in your mapping.
You can do it in the following way:
#Table
#Entity
public class ExampleTable implement Serializable
{
// ...
#Column(name = "'key'") // or #Column(name = "\"key\"")
private String key;
//...
}

Hibernate generates invalid SQL query with MySQL

I have the following JPA entity classes (example case). A House belongs on a single Street. A Street has many Houses.
#Entity
public class House {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Integer id;
public String name
#ManyToOne
public Street street;
}
#Entity
public class Street {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Integer id;
#OneToMany(mappedBy="street")
public Set<House> houses;
}
I have the generation type set to identity, which is supposed to auto assign a new ID.
When creating a new House with a new Street, I have to first create and persist Street, followed by House. This is because I do not have CascadeType set to PERSIST, so it has to be done manually [1]. However, while inserting a newly created Street:
Street street = new Street();
entityManager.persist(street);
Hibernate/JPA generates the following SQL query:
insert into Street default values
which MySQL doesn't like.
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'default values' at line 1
Any ideas why? I'm using Java 6, MySQL 5.0.67 with Hibernate's implementation of JPA (version 3.2.1.ga).
[1] EJB 3 in Action pages 318-319
If you don't have an error in your SQL statement, then you might want to check your table column name as it can contain a predefined name that Mysql uses; for example 'column' which can't be used as a table column name
Standard SQL specifies this optional syntax for INSERT:
INSERT INTO <Table Name> DEFAULT VALUES
This is legal SQL syntax, supported, for example, by Microsoft SQL Server, PostgreSQL, and SQLite, but not by Oracle, IBM DB2, or MySQL.
MySQL supports other syntax that achieve the same result:
INSERT INTO <Table Name> () VALUES ()
INSERT INTO <Table Name> (col1, col2, col3) VALUES (DEFAULT, DEFAULT, DEFAULT)
In Hibernate, you should configure the SQL dialect properly, and it's up to Hibernate to generate valid SQL for the target RDBMS brand.
import org.hibernate.cfg.Configuration;
Configuration cfg = new Configuration();
cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect");
You can also specify properties by placing a file named hibernate.properties in a root directory of the classpath.
Another situation when you might have this exception is when you have reserved words as columns for the table. For example 'to' and 'from' are not suitable clumn names for MySQL. It is obviously bug in Hibernate, that it doesn't check such columns and moreover continues to work with no error even if table is not created.
Make sure spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialecthas correct version of MySQL

Categories

Resources