I want to use datepicker to select range of dates. This range of dates is then queried in the database where the sum is counted...
My attempt:
public static int dateRange(){
int value = 0;
PreparedStatement stmt = null;
try {
Connection connection = DriverManager.getConnection("", "", "");
stmt = connection.prepareStatement("SELECT SUM(cost) FROM Items WHERE expiration_date between '" + Budget.datePicker1.getValue() + "' and '" + Budget.datePicker2.getValue() + "'");
ResultSet result = stmt.executeQuery();
result.next();
String sum = result.getString(1);
value = Integer.parseInt(sum);
} catch (Exception e){
value += 0;
}
return value;
}
It works. It returns the total if the days are there so to speak. If there are no days in the database as selected in the DatePicker then 0 pops up... But it looks messed up (catch block) and I was wondering if anyone could help me with an alternative solution?
First, since the value returned by the query is an integer value, there is no need to read it as a string and parse it. Just use result.getInt(...).
Second, if you are going to use a PreparedStatement, use it to properly set parameters, instead of building the query out of concatenated strings. Doing the latter exposes your application to SQL injection attacks.
If none of your dates are in range, then the SQL query will return NULL. Calling getInt() on column in a result set that is NULL will return 0, so you will get the result you want in that case anyway. If the previous value you got from a result set was SQL NULL, then calling result.wasNull() will return true, so if you really did need to handle that case separately, you could use that mechanism to do so.
You can do:
public static int dateRange(){
int value = 0;
// Use try-with-resources to make sure resources are released:
try (
Connection connection = DriverManager.getConnection("", "", "");
PreparedStatement stmt = connection.prepareStatement(
"SELECT SUM(cost) FROM Items WHERE expiration_date between ? and ?");
) {
stmt.setDate(1, Date.valueOf(Budget.datePicker1.getValue()));
stmt.setDate(2, Date.valueOf(Budget.datePicker2.getValue()));
ResultSet result = stmt.executeQuery();
result.next();
// Note that if there are no values in range, the SQL result will be NULL
// and getInt() will return 0 anyway.
value = result.getInt(1);
// however, if you need to explicitly check this and do something different
// if nothing is in range, do:
if (result.wasNull()) {
// nothing was in range...
}
} catch (SQLException e){
// this actually indicates something went wrong. Handle it properly.
Logger.getGlobal().log(Level.SEVERE, "Error accessing database", e);
// inform user there was a db error, etc...
}
return value;
}
Related
public <E> List viewc(String a,String c) {
List l1=new ArrayList();
try {
con = utilimpl.openSession();
if(con != null)
{
st = con.beginTransaction();
Query q=con.createQuery("FROM "+a+" WHERE cdate="+c+"");
l1=q.list();
st.commit();
}
else
{
System.out.println("no connection found!!");
}
} catch (HibernateException e) {
e.printStackTrace();
if(st != null)
{
st.rollback();
}
}
return l1;
}
Below code is doget method code of servlet.i want to get list of data.cdate is column of my database and datatype is timestamp in mysql.
SimpleDateFormat k=new SimpleDateFormat("yyyy-MM-dd");
Date s=new Date();
String c=k.format(s);
List<userModel> ln=d.viewc("userModel",c);
request.setAttribute("list",ln);
Since cdate is of timestamp type, it consists of date + time and you are trying to compare over date part only with equality.
Try something like this:
Query q=con.createQuery("FROM "+a+" WHERE DATE(cdate)=DATE("+c+")");
EDIT: In order for the comparison to work, value of c and cdate should be in same format. In order to achieve this, query can be modified as follow:
Query q=con.createQuery("FROM "+a+" WHERE DATE_FORMAT(DATE(cdate),'%Y-%m-%d')="+c);
Here c should be in format : 'yyyy-mm-dd', eg '2019-01-19'
DATE_FORMAT would convert the resulted date into the desired format as string value, and now comparison with 'c' should hold good.
Hi there I'm having issues with SQL updating player stats which makes very huge lag/timings drop I'm updating the stats on server stop this is my stats code:
public int getDeaths(Player p) {
if (!plugin.getConfig().getBoolean("mysql")) {
return plugin.data.getConfig().getInt("Deaths." + p.getUniqueId() + ".death");
}
if (plugin.getConfig().getBoolean("mysql")) {
int res = 0;
ResultSet result = getMainSQLConnection()
.executeQuery("SELECT * FROM `Account` WHERE playername='" + p.getName() + "'", false);
try {
if (result.next()) {
res = Integer.parseInt(result.getString("deaths"));
}
} catch (SQLException localSQLException) {
}
return res;
}
return 0;
}
public void setDeaths(Player p, int number) {
if (!plugin.getConfig().getBoolean("mysql")) {
plugin.data.getConfig().set("Deaths." + p.getUniqueId() + ".death", number);
plugin.data.save();
}
if (plugin.getConfig().getBoolean("mysql")) {
plugin.sqlConnection.executeUpdate(
"UPDATE `Account` SET deaths='" + number + "' WHERE playername='" + p.getName() + "'");
}
}
If you're getting the death count for a command or something that doesn't require the value to be returned immediately, use a asynchronous scheduler to run the code on a separate thread. For a command you'd do something like this when it is executed:
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try {
int deaths = getMainSQLConnection()
.executeQuery("SELECT * FROM `Account` WHERE playername='" + p.getName() + "'", false)
.getInt("deaths");
player.sendMessage("Player Deaths: " + deaths);
} catch (SQLException ex) {
player.sendMessage(ChatColor.RED + "That player does not exist!");
}
});
Otherwise, if you need the value in the code for whatever reason, you can use a connection pool such as HikariCP. A connection pool will allow you to maintain multiple connections to your database so when you need to execute a query you don't have to establish a new connection every time (which is what will cause most of the lag).
Better yet, use an asynchronous task in tandem with the connection pool. Here's a good tutorial for learning how to use HikariCP with Bukkit: https://www.spigotmc.org/threads/tutorial-implement-mysql-in-your-plugin-with-pooling.61678
As a side note, for basically zero performance impact on the server, you can load the data asynchronously when a player logs in (using the AsyncPlayerPreLoginEvent). Then store it in memory when they actually join the server (PlayerLoginEvent or PlayerJoinEvent), and remove it when they quit. This way you access the data through memory while they're logged in rather than the database. This is much more complicated and also requires a lot of code to implement correctly though, so I'm not going to go into detail here.
I am using the below code in google apps script to insert employee record from a Google Sheet into a mysql database.
The stored procedure [dbo].[insertemployee] accepts "#empname" parameter.
var empname = 'test';
var mysqldbconn = Jdbc.getConnection(url,username,password);
var mysqlquery = mysqldbconn.createStatement();
callstoredprocedure = "{call [dbo].[testemployee](?)}";
mysqlquery = mysqldbconn.prepareCall(callstoredprocedure);
mysqlquery.setString(1, empname);
mysqlquery.executeUpdate();
This gives me this error "Must declare the scalar variable "#empname"".
Perhaps reading this might help you:
Calling MySQL Stored Procedures from JDBC
This is where you go wrong:
mysqlquery = mysqldbconn.prepareCall(vstrSQLStatement);
You don't use the declared 'callstoredprocedure'.
Read example below:
public static void getSkills(int candidateId) {
//
String query = "{ call get_candidate_skill(?) }";
ResultSet rs;
try (Connection conn = MySQLJDBCUtil.getConnection();
CallableStatement stmt = conn.prepareCall(query)) {
stmt.setInt(1, candidateId);
rs = stmt.executeQuery();
while (rs.next()) {
System.out.println(String.format("%s - %s",
rs.getString("first_name") + " "
+ rs.getString("last_name"),
rs.getString("skill")));
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
}
Let me explain:
The query is defined, similar to your call accepting 1 parameter returning no value. Then it is used in the: conn.prepareCall() , and then the parameter is set to the statement and then it is executed.
As I mentioned, you should do this:
mysqlquery = mysqldbconn.prepareCall(callstoredprocedure);
Please let me know, if this fixed your problem.
I have this sql statement:
selectAllUsersByCriteria = connection.prepareStatement(
"SELECT * FROM Users WHERE ? = ?" );
And the follow method running the statement:
public ArrayList<User> getUsersByCriteria(String 1criteria, String 2criteria)
{
ArrayList<User> results = null;
ResultSet resultSet = null;
try
{
selectAllUsersByCriteria.setString( 1, 1criteria);
selectAllUsersByCriteria.setString( 2, 2criteria);
// executeQuery returns ResultSet containing matching entries
resultSet = selectAllUsersByCriteria.executeQuery();
results = new ArrayList< User >();
while ( resultSet.next() )
{
results.add( new User( resultSet.getString( "userName" ),
resultSet.getString( "Password" ),
resultSet.getBoolean( "AdminRights" ),
resultSet.getDouble( "Balance" )
) );
} // end while
} // end try
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
finally
{
try
{
resultSet.close();
} // end try
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
close();
} // end catch
} // end finally
return results;
}
It doesn't work. I figure it is the first ? that is the issue. Isn't it possible to set the WHERE ? as a ?. Can it be solved in another way.
It is a table I want to show, but it should only be show the users follow it meet the two criteria.
You would need to inject the column name directly into the string. That would open you up to a SQL injection attack, so I'd recommend querying (and probably caching) the table's schema info (specifically found in INFORMATION_SCHEMA.COLUMNS).
This way you can make sure that your user-submitted column name matches one of the column names in your table before injecting it into the script by seeing if it's in your list of available columns.
I'm just wondering how to get rid of this error:
try {
int ppointd;
String nazwa;
int smr;
int zab;
PreparedStatement pktUpdate = Main.c.prepareStatement("SELECT * FROM `staty` ORDER BY `pkt` DESC LIMIT 10");
ResultSet rs1 = pktUpdate.executeQuery();
for(int i = 1; i<11; i++) {
rs1.next();
nazwa = rs1.getString("Nazwa");
zab = rs1.getInt("zab");
smr = rs1.getInt("smr");
ppointd = rs1.getInt("pkt");
p.sendMessage("§a"+i+". §e" + nazwa + " §b- §6PKT: §7[§4" + ppointd+ "§7] §6ZAB: §7[§4"+zab+"§7] §6SMR: §7[§4"+smr+"§7]");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I made some digging and I know it's about this String, but I have no clue how to skip this and have same output. Any ideas?
You call rs1.next() in a loop from 1 to 10, but what if your SELECT query returns fewer than 10 rows?
When you call rs1.next() you need to test if that method returns false, and if so, break out of the loop.
For example, it's more common to code it the following way instead of using a for loop:
while (rs1.next()) {
. . .
}
That way the loop automatically stops when there are no more rows.