I am trying to determine the ranking of a user by their score from an external database using Java and SQL. Here's what I have so far:
public int findRanking(User user){
int count =0;
if (c == null) {
c = getConnection();
}
try{
Statement s =c.createStatement();
String query="SELECT * FROM USERS ORDER BY SCORE DESC";
ResultSet rs = s.executeQuery(query);
while(rs.next()){
..
}
}catch (Exception e) {
System.out.println("exception: " + e);
}
I'm not sure how to operate the while loop to return the ranking. If anybody has any suggestions I would really appreciate it.
First off, the method you provided has a syntax error, you close the function body after c=getConnection();
You should read the javadocs for resultset here.
You can read your score by doing:
if (rs.next()) {
score = rs.getInt("SCORE");
}
no need for a while loop, since you only want the score of one user :)
Also, this method does not return the score of a given user, it returns the highest score of all users. You should modify your query to do something along the lines of:
String query="SELECT * FROM USERS WHERE USERID = " + user.getId() + "ORDER BY SCORE DESC";
Do you see why?
Try following:
SET #ranking := 0;
SELECT #ranking := #ranking+1 as ranking, * FROM (SELECT * FROM USERS ORDER BY SCORE DESC)
With this you will not need a while loop to determine ranking.
recommendation: instead of *, list the fields you are expecting -- query is faster then.
for a single user:
SET #ranking := 0;
SELECT * from (SELECT #ranking := #ranking+1 as ranking, * FROM (SELECT * FROM USERS ORDER BY SCORE DESC) U) W where userId='89'
Final code. Thanks a lot guys for your help:
public int findRanking(String username){
int rank =1;
if (c == null) {
c = getConnection();}
try{
Statement s =c.createStatement();
String query="SELECT * FROM USERS ORDER BY SCORE DESC";
ResultSet rs = s.executeQuery(query);
while(rs.next()){
String current=rs.getString("USERNAME");
if(username.equals(current)){
return rank;
}
else{
rank++;
}
}
}catch (Exception e) {
System.out.println("exception: " + e);
}
return rank;
}
Related
I am trying to make a username only register if that name is not taken, using JDBC connection and checking on SQL Database.
I have the code that checks for the
SELECT * FROM user
WHERE username = 'jessica';
and it finds 2 rows;
Searched a lot and found that with getFetchSize() it would give me the number of rows, and if it finds null it would return 0.
It is always returning 0, I don't know why, because I have the usernames taken twice, it lets me add me always...
https://prnt.sc/galyqo
public int nameAvailable(MyUserApp app, String name) throws SQLException{
String sql = "SELECT * FROM user \n WHERE username = '"+ name +"';";
Statement st = app.getCon().createStatement();
ResultSet rs = st.executeQuery(sql);
int numResults = rs.getFetchSize();
return numResults;
}
This is the register code:
private void RegisterButtonActionPerformed(java.awt.event.ActionEvent evt) {
String username, password, address, dob;
boolean status;
String u;
try {
username = newUsernameField.getText();
password = passwordField2.getText();
address = addressField.getText();
dob = dateofbField.getText();
int no= 5;
if( username.isEmpty() || password.isEmpty() || password.length() < 6 ){
jLabel6.setText("The information you typed in is not valid. ");
status = false;
showTableDB.setText(""+status);
}
else{
no = this.app.nameAvailable(app, username);
jLabel6.setText(no+"");
if(no == 0){
jLabel6.setText("Registered your account, "+username+"!" + no);
status = this.app.registerUser(app, username, password, dob, address);
u = this.app.showInfo(app, username);
showTableDB.setText(u);
no = this.app.nameAvailable(app, username);
}
else{
showTableDB.setText("That username is token. Please choose a different one.");
}
}
} catch (SQLException ex) {
Logger.getLogger(UserAppUI.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(UserAppUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
Resolved. Solution:
public int getNCount(MyUserApp app, String name) throws SQLException{
String sql = "SELECT COUNT(*) FROM user \n WHERE username = '"+ name +"';";
int rowCount;
PreparedStatement st = app.getCon().prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet r = st.executeQuery(sql);
r.next();
// get the number of rows from the result set. On the db it will show a table with "count(*)" and the #counts
rowCount = r.getInt("count(*)");
r.close();
st.close();
return rowCount;
}
By calling these statement on the code:
r.next()
and then
rowCount = r.getInt("count(*)");
I was able to get the 2nd column of the count(*) SQL Statement.
The fetch size is not the same thing as the number of rows. The fetch size is just a way of limiting how many rows at a time will be fetched from the database.
There's no easy way to check the number of rows returned by a select statement. If you really need to know how many rows there are, in the case there's more than one, then one approach would be to iterate through the result set, copying the information that you need from each row into memory; then check the amount of data that you copied at the end.
Alternatively, if you don't actually need any data from the rows themselves, you could try a statement like SELECT count(*) FROM user WHERE username = ?.
One more thing - you need to read about SQL injection attacks. This is where a hacker uses your code to run SQL that they shouldn't. The code you've shown here is vulnerable to an SQL injection attack. But that's another question entirely.
Resolved. Solution:
public int getNCount(MyUserApp app, String name) throws SQLException{
String sql = "SELECT COUNT(*) FROM user \n WHERE username = '"+ name +"';";
int rowCount;
PreparedStatement st = app.getCon().prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet r = st.executeQuery(sql);
r.next();
// get the number of rows from the result set. On the db it will show a table with "count(*)" and the #counts
rowCount = r.getInt("count(*)");
r.close();
st.close();
return rowCount;
}
By calling these statement on the code:
r.next()
and then
rowCount = r.getInt("count(*)");
I was able to get the 2nd column of the count(*) SQL Statement.
How can an SQL query return data from multiple tables?
for ex. my sql query suppose to list all students in specific classroom
but instead it shows only 1 student. Can this be done by system output?
if (forms.Validation.textNotEmpty(tfId)) {
try {
ResultSet rs = hogDB.getData("select * from student where sleepRoom = ("+tId.getText()+");");
if (rs.next()) {
tfStudentId1.setText(rs.getString("student_id"));
tfForNamne1.setText(rs.getString("fornamne"));
tfAfterNamne1.setText(rs.getString("AfterNamn"));
tfSleep1.setText(rs.getString("sleepRoom"));
}
} catch(Exception e) {
e.printStackTrace();
}
}
To find out whether you are really retrieving just one student or several, here’s a suggestion for a piece of test code.
try {
ResultSet rs = hogDB.getData("select * from student where sleepRoom = ("
+ tId.getText() + ");");
int count = 0;
while (rs.next()) {
System.out.format("%-10s%-20s%-20s%-8s%n",
rs.getString("student_id"), rs.getString("fornamne"),
rs.getString("AfterNamn"), rs.getString("sleepRoom"));
count++;
}
System.out.println("" + count + " students retrieved");
} catch(Exception e) {
e.printStackTrace();
}
Another possible issue, is tId.getText() a number? If it isn’t, you should probably enclose it in single quotes in the query. In any case, the recommended way is to pass a value to the database is through a ? placeholder and some setXx() call on the prepared statement.
I am still a beginner in Java and stackoverflow.
I coded a plugin for a minecraft server in java, using mysql for a stats system (Kills deaths points)
I want to know, how i can get the player with the highest amount of "Points", so i like to get the "Playername" where "Points" is the highest.
I also would like to get the 2nd highest, 3rd highest etc.
I used prepared statements like:
public static int getPoints(String Playername) {
int Points = 0;
try {
PreparedStatement st = con
.prepareStatement("SELECT Points FROM FFA WHERE UUID = '"
+ PlayerUtil.getUUID(Playername) + "'");
ResultSet rs = st.executeQuery();
if (rs.next()) {
Points = rs.getInt("Points");
} else {
Points = 0;
}
} catch (SQLException e) {
e.printStackTrace();
}
return Points;
}
If you are able to help me, that would be extremely nice!
Thanks for your time!
PS:
My SQL structure:
Playername varchar(64)
UUID varchar(64)
Kills int
Deaths int
Points int
You can use the following statement to do that:
select playername from FFA order by points desc limit 10;
That will return the top 10 players
Or you could do something like
select playername from FFA where points >= 1337 order by points DESC;
Then you can go through every entry calling rs.next() in a loop. First fetch with rs.next() will get you the player with more points because you used order by.
So the code would look like this:
public static String getTopPlayer() {
int limit = 10;
try {
preparedstatement st = con
.preparestatement("select * from FF order by points desc limit "
+ limit);
resultset rs = st.executequery();
if (rs.next()) {
name = rs.getString("playername");
//if rs.next() rs.getString("playername"); <-- returns second
//if rs.next(); rs.getString("playername"); <-- returns third
} else {
name = null;
}
} catch (sqlexception e) {
e.printstacktrace();
}
return name;
You can try something like this in SQL :
select playername from FFA where points=(select max(points) from FFA);
This query can return more than one row...
Ok, so for example my table would look like:
┌──────┬────────┬─────────────┬───────────┐
│UserID│Username│CurrentLeague│TotalPoints│
├──────┼────────┼─────────────┼───────────┤
│1 │Elliot │randomLeague │15 │
├──────┼────────┼─────────────┼───────────┤
│2 │Callum │randomLeague │20 │
├──────┼────────┼─────────────┼───────────┤
│3 │Rory │testLeague │17 │
├──────┼────────┼─────────────┼───────────┤
│4 │Admin │NULL │0 │
├──────┼────────┼─────────────┼───────────┤
│5 │Steve │randomLeague │21 │
└──────┴────────┴─────────────┴───────────┘
And here is my code in my Java project for the class that I'm using here.
public int getLeaguePosition(String username)
{
try
{
int leaguePosition = 0;
String leagueName = getLeague(username);
System.out.println("League Name: " + leagueName);
ArrayList<SortingUser> sortingUser = new ArrayList<SortingUser>();
String query = "SELECT * FROM Users WHERE CurrentLeague = ?";
preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, leagueName);
resultSet = preparedStatement.executeQuery();
while(resultSet.next())
{
String retrievedUsername = resultSet.getString("Username");
System.out.println(retrievedUsername);
SortingUser retrievedUser = new SortingUser(retrievedUsername);
sortingUser.add(retrievedUser);
}
Collections.sort(sortingUser);
for(int i = 0; i < sortingUser.size(); i++)
{
SortingUser retrievedSortingUser = sortingUser.get(i);
String retrievedUsername = retrievedSortingUser.getUsername();
if(retrievedUsername.contains(username) && username.contains(retrievedUsername))
{
leaguePosition = i + 1;
System.out.println("League Position for " + username.toUpperCase() + " is " + leaguePosition);
return leaguePosition;
}
}
}
catch(Exception e)
{
System.out.println("Couldn't get league position for: " + username);
e.printStackTrace();
}
return 0;
}
and if I gave it "Rory" as the username it would return the records with ID 3, 4 and 5 rather than just 3 when calculating the position.
Why does it do this? I'm fairly sure my code is correct because when I copy that exact SQL query into phpMyAdmin it works perfectly.
I am not sure what you were trying to do there with the SortingUser, but I'd go with much simpler code, and let SQL do its own sorting. It's usually very efficient at that, especially if you have the proper indexes on the table.
public int getLeaguePosition(String username)
{
try
{
String leagueName = getLeague(username);
System.out.println("League Name: " + leagueName);
// This is returning all the users in the same league sorted by descending points.
String query = "SELECT * FROM Users WHERE CurrentLeague = ? ORDER BY TotalPoints DESC";
preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, leagueName);
resultSet = preparedStatement.executeQuery();
int leaguePosition = 0;
while(resultSet.next())
{
// Since the result set is already sorted, the first player has the most points, so his
// leaguePosition is one. The second has the next best number of points, so his position
// is two, and so on. So we keep the leaguePosition var based on the number of the row.
leaguePosition++;
// And if the user name retrieved actually matches the one that we passed, then this is
// his league position.
String retrievedUsername = resultSet.getString("Username");
if ( retrievedUsername.equals( username ) ) {
break;
}
}
resultSet.close();
return leaguePosition;
}
catch(Exception e)
{
System.out.println("Couldn't get league position for: " + username);
e.printStackTrace();
}
return 0;
}
Have you implemented Comparable interface in SortingUser class?
Collections.sort() will not sort the objects, if you haven't implemented Comparable in your class.
for simple example check this out!!
I have a MSSQL database and am running the following query:
select * from projects; select * from user
The above query returns two result sets at once, and I cannot fire both queries separately. How can I handle both the result set at once in a Java class?
Correct code to process multiple ResultSets returned by a JDBC statement:
PreparedStatement stmt = ...;
boolean isResultSet = stmt.execute();
int count = 0;
while(true) {
if(isResultSet) {
rs = stmt.getResultSet();
while(rs.next()) {
processEachRow(rs);
}
rs.close();
} else {
if(stmt.getUpdateCount() == -1) {
break;
}
log.info("Result {} is just a count: {}", count, stmt.getUpdateCount());
}
count ++;
isResultSet = stmt.getMoreResults();
}
Important bits:
getMoreResults() and execute() return false to indicate that the result of the statement is just a number and not a ResultSet.
You need to check stmt.getUpdateCount() == -1 to know if there are more results.
Make sure you either close the result sets or use stmt.getMoreResults(Statement.CLOSE_CURRENT_RESULT)
You can use Statement.execute(), getResultSet();
PreparedStatement stmt = ... prepare your statement result
boolean hasResults = stmt.execute();
while (hasResults) {
ResultSet rs = stmt.getResultSet();
... your code parsing the results ...
hasResults = stmt.getMoreResults();
}
Yes, You can. See this MSDN article
https://msdn.microsoft.com/en-us/library/ms378758(v=sql.110).aspx
public static void executeStatement(Connection con) {
try {
String SQL = "SELECT TOP 10 * FROM Person.Contact; " +
"SELECT TOP 20 * FROM Person.Contact";
Statement stmt = con.createStatement();
boolean results = stmt.execute(SQL);
int rsCount = 0;
//Loop through the available result sets.
do {
if(results) {
ResultSet rs = stmt.getResultSet();
rsCount++;
//Show data from the result set.
System.out.println("RESULT SET #" + rsCount);
while (rs.next()) {
System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));
}
rs.close();
}
System.out.println();
results = stmt.getMoreResults();
} while(results);
stmt.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
I've tested that and it works fine.
Before use java, you need look at the RESULT SETS clause.
MSSQL has this feature that can help you with your java code, in a more practical way.
This example will exec two queries:
EXEC('SELECT id_person, name, age FROM dbo.PERSON; SELECT id_url, url FROM dbo.URL;')
WITH RESULT SETS
(
(
id_person BIGINT,
name VARCHAR(255),
age TINYINT
),
(
id_url BIGINT,
url VARCHAR(2000)
)
);
You can use stored procedures with RESULT SETS as well.
More about: https://technet.microsoft.com/en-us/library/ms188332(v=sql.110).aspx
public static void executeProcedure(Connection con) {
try {
CallableStatement stmt = con.prepareCall(...);
..... //Set call parameters, if you have IN,OUT, or IN/OUT parameters
boolean results = stmt.execute();
int rsCount = 0;
//Loop through the available result sets.
while (results) {
ResultSet rs = stmt.getResultSet();
//Retrieve data from the result set.
while (rs.next()) {
....// using rs.getxxx() method to retrieve data
}
rs.close();
//Check for next result set
results = stmt.getMoreResults();
}
stmt.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
The UNION ALL query allows you to combine the result sets of 2 or more "select" queries. It returns all rows (even if the row exists in more than one of the "select" statements).
Each SQL statement within the UNION ALL query must have the same number of fields in the result sets with similar data types.........
select * from projects
UNION ALL
select * from user
The answer: it is NOT possible. The only way: Run them as separate queries.