I'm working on a project where a user can assemble the components of a yoga class. It's spread across several files and thus too large to put it all here. The trouble I'm having is in one method where I need to iterate over the horizontal columns of a result set that is returning only ONE ROW from a MySQL database.
I understand that I have to position the cursor on the first row of the result set (which I believe I am doing). Since I have only one row in the result set (my variable is rset), I should be using rset.next() only one time, correct? And then I should be able to use a simple loop to iterate over each column and append the value to my String Builder. I want to skip the first column and append each subsequent value until the loop reaches columns with null values. I cannot find why my code keeps returning a "Before start of result set" exception.
Can anyone spot anything wrong?
I'll post the method as well as the method called by this method. (I posted this in a different question, but I believe the nature of my question has changed, so I'm re-posting this with a different title.)
// Query that returns the poses within a specific section
public String listPosesInSection(String tableName, String sectionName) {
String strList;
StringBuilder strBuilderList = new StringBuilder("");
// Run the query
try {
statement = connection.createStatement();
// Query will collect all columns from one specific row
rset = statement.executeQuery("SELECT * FROM " + tableName + " WHERE " + tableName + "_name = '" + sectionName + "'");
rset.next();
System.out.println("Column count is " + countColumnsInTable(tableName));
for (int i = 2; i <= countColumnsInTable(tableName); i++) {// First value (0) is always null, skip first column (1)
System.out.println("test");
strBuilderList.append(rset.getString(i) + "\n"); // This is line 126 as indicated in the exception message
}
} catch (SQLException e) {
e.printStackTrace();
}
strList = strBuilderList.toString();
return strList.replaceAll(", $",""); // Strips off the trailing comma
}
// Method for getting the number of columns in a table using metadata
public int countColumnsInTable(String sectionType) {
int count = 16;
try {
statement = connection.createStatement();
rset = statement.executeQuery("SELECT * FROM " + sectionType);
rsMetaData = rset.getMetaData();
count = rsMetaData.getColumnCount();
} catch (SQLException e) {
e.printStackTrace();
}
return count;
}
And here is the first part of the exception message:
Column count is 26
java.sql.SQLException: Before start of result set
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1078)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:975)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:920)
at com.mysql.jdbc.ResultSetImpl.checkRowPos(ResultSetImpl.java:855)
at com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.java:5773)
at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5693)
at YogaDatabaseAccess.listPosesInSection(YogaDatabaseAccess.java:126)
at YogaSectionDesigner$5.actionPerformed(YogaSectionDesigner.java:231)
Looks to me like you're re-using the rset between your two methods. So when countColumnsInTable has completed, the rset variable is pointing to a different result set than it was before, in listPosesInSection. And that result set has not been advanced with next, hence the error message you're getting. You probably want to assign it to a local ResultSet within that method instead.
public int countColumnsInTable(String sectionType) {
int count = 16;
try {
Statement statement = connection.createStatement();
ResultSet rset = statement.executeQuery("SELECT * FROM " + sectionType);
ResultSetMetaData rsMetaData = rset.getMetaData();
count = rsMetaData.getColumnCount();
} catch (SQLException e) {
e.printStackTrace();
}
// Remember to clean up
return count;
}
try this
public String listPosesInSection(String tableName, String sectionName) {
String strList;
StringBuilder strBuilderList = new StringBuilder("");
// Run the query
try {
statement = connection.createStatement();
// Query will collect all columns from one specific row
rset = statement.executeQuery("SELECT * FROM " + tableName + " WHERE " + tableName + "_name = '" + sectionName + "'");
while (rset.next()){
System.out.println("Column count is " + countColumnsInTable(tableName));
for (int i = 2; i <= countColumnsInTable(tableName); i++) {// First value (0) is always null, skip first column (1)
System.out.println("test");
strBuilderList.append(rset.getString(i) + "\n");
}
}
} catch (SQLException e) {
e.printStackTrace();
}
strList = strBuilderList.toString();
return strList.replaceAll(", $",""); // Strips off the trailing comma
}
rset is a ResultSet object
i think you are using the same ResultSet object in listPosesInSection and also in countColumnsInTable
so what is happening here is in listPosesInSection rset holds a result and you have also move the cursor but again in countColumnsInTable you are using the same rset so it is overwritten ie it holds a new result now, you are getting the number of columns but since it holds a new result now the cursor will be before the 1st record so use different Resultset object in countColumnsInTable
Related
How can I query data from my database and assign it to an array of strings? In this attempt I noticed I would receive an out of bounds error before I included the resultSet.next() call since it seems that ResultSet starts at 0 and is not called like a list / array (meaning you can access the contents with its index).
public String[][] retrieveNameAndLocation() {
final String table = "customers";
try {
ResultSet resultSet = statement.executeQuery(
"SELECT " +
"first_name," +
"location" +
" FROM " + table
);
resultSet.next();
final String[] names = (String[]) (resultSet.getArray(1).getArray());
final String[] location = (String[]) (resultSet.getArray(2)).getArray();
final String[][] nameAndCountry = {names, location};
resultSet.close();
return nameAndCountry;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
Anyways the above code resulted in a SQLFeatureNotSupportedException. My next attempt was to simply call the the columns by name since I noticed it was an option inside of getArray, however that also resulted in the not supported exception.
public String[][] retrieveNameAndLocation() {
final String table = "customers";
try {
ResultSet resultSet = statement.executeQuery(
"SELECT " +
"first_name," +
"location" +
" FROM " + table
);
resultSet.next();
final String[] names = (String[]) (resultSet.getArray("first_name").getArray());
final String[] location = (String[]) (resultSet.getArray("location")).getArray();
final String[][] nameAndCountry = {names, location};
resultSet.close();
return nameAndCountry;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
I am not really sure why I need to include resultSet.next() because it seems like it's just broken since why would they include an option to query columns if they forced you to loop through the indexes?
I think you misunderstand the purpose of method getArray. Some DBMSs, like Oracle, have "array" data types. Hence the getArray method – to query a database table column whose type is an array type. I have no experience with MySQL but it appears that it does not have an array type. Hence the JDBC driver for MySQL does not need to implement the getArray method and that's why you get the SQLFeatureNotSupportedException.
You need to iterate through the ResultSet and build up your array. However since you usually don't know how many rows there are in a ResultSet, I usually use a List and then, if required, convert it to an array because when you declare an array you need to know its size.
I would also define a record and declare a List of records.
(Note that below code is not compiled and not tested since I don't have your database and I can't simulate it since the code in your question is not a minimal, reproducible example.)
public record NameAndCountry(String name, String location) {
public static java.util.List<NameAndCountry> retrieveNameAndLocation() {
final String table = "customers";
try {
ResultSet resultSet = statement.executeQuery(
"SELECT " +
"first_name," +
"location" +
" FROM " + table
);
java.util.List<NameAndCountry> list = new java.util.ArrayList<>();
while (resultSet.next()) {
String name = resultSet.getString(1);
String location = resultSet.getString(2);
NameAndCountry row = new NameAndCountry(name, location);
list.add(row);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
}
I have an SQL query in the following Java Code:
try {
Statement st = conn.createStatement();
try {
st.execute("SELECT * FROM students WHERE course_id =1");
} finally {
// st.close();
}
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
When I execute this code, I don't see anything in the console.
I want to put the results to a Hashmap or print them to see the values, at least.
How can I implement printing to the console or storing the results in a Map?
It would really help to know the column information (labels, amount, types), but maybe, you can do what you want having the following code as a hint or template and reading the comments carefully:
public static void main(String[] args) {
// provide the query as String with a question mark for the parameter
String query = "SELECT * FROM students WHERE course_id = ?";
// and provide the parameter value
int id = 1;
// use a try with resources in order to automatically close the resources
try (PreparedStatement ps = conn.prepareStatement(query)) { // WON'T COMPILE due to conn
// set the position and the parameter to the query
ps.setInt(1, id);
// execute the query and receive the results
ResultSet rs = ps.executeQuery();
/*
* since we neither know how many columns "* FROM students" returns,
* nor what types their values have, we have to determine them programmatically
*/
// that means we need to receive them from the meta data of the result set
ResultSetMetaData rsmd = rs.getMetaData();
// provide a StringBuilder for the output of the header information
StringBuilder headerInfoBuilder = new StringBuilder();
// extract the column information
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
headerInfoBuilder.append(rsmd.getColumnLabel(i))
.append(" [")
.append(rsmd.getColumnType(i))
.append("]")
.append(";");
}
// remove the last semicolon
String headerInfo = headerInfoBuilder.toString()
.substring(0, headerInfoBuilder.length() - 1);
// and print the header information
System.out.println(headerInfo);
// provide a variable that counts the rows
int rowCount;
// then iterate the results
while (rs.next()) {
/*
* print the results here or store them in a data structure,
* depends on the types and amount of columns
*/
rowCount++;
}
// output the row count
System.out.println(rowCount + " rows received");
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
Try this :-
try {
Statement st = conn.createStatement();
try {
ResultSet rs=st.executeQuery("SELECT * FROM students WHERE course_id =1");
while(rs.next()) {
//Your logic to put in map goes here
}
} finally {
// st.close();
}
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
I am trying to select values from a row in my MySQL table.
SELECT fortnite,psn,steam,twitch,xbox,youtube
FROM `social_media`
WHERE id = '16483378715464928'
When I try to convert the result into a string, the ResultSet only receives the first "fortnite" row. My question is, how do I retrieve the following columns and put them all into one string to return.
Here is my example code:
public static String getSocialMedia(String id) {
String ret = "";
int i = 1;
try {
Statement stmt = null;
ResultSet resultSet = null;
getConnection();
stmt = con.createStatement();
resultSet = stmt.executeQuery("SELECT fortnite,psn,steam,twitch,xbox,youtube FROM `social_media` WHERE id ='" + id + "'");
while(resultSet.next()) {
ret += resultSet.getString(i) + " ";
i++;
}
if(resultSet != null) {
resultSet.close();
}
if(stmt != null) {
stmt.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}
This is happening due to this.
while(resultSet.next()) {
ret += resultSet.getString(i) + " ";
i++;
}
In the above code inside while you need to fetch all the values either by name or index. next() function gives you the complete row not a single column.
You should change it to:
while(resultSet.next()) {
for(i = 1, i <=6, i++){
ret += resultSet.getString(i) + " ";
}
}
When i try to convert the result into a string, the ResultSet only
receives the first "fortnite" row. My question is, how do i retrieve
the following columns and put them all into one string to return.
Terminology is important here, because misunderstanding terminology may lead you to misinterpret documentation. In this case, the important terminology distinction is "row" vs. "column".
Your query SELECTs fortnite,psn,steam,twitch,xbox,youtube. Those six identifiers define six columns that each row in your result set will have. It looks like your particular query is selecting by the table's primary key, so you'll only ever have zero or one row, but other queries can return multiple rows.
You want to extract the values of all six columns of one row, but you iterate while(resultSet.next()), and ResultSet.next() moves the result set to the next row, if any, not the next column. Since you have only one row, the loop terminates after only one iteration.
It looks like you want something more like this:
if (resultSet.next()) {
for (i = 1; i <= 6; i++) {
ret += resultSet.getString(i) + " ";
}
}
The if (resultSet.next()) is necessary to move the result set to the first row, and to detect when there isn't any. Then you iterate over the columns of the result, whose number you know statically, based on the query.
my textfield is called pruebamax
With this function I make the connection with the database
public ResultSet getmax() {
ResultSet r = null;
try {
String sql = "select count(*) as Cantidad from tbl_padre";
System.out.println(sql);
Statement st = cx.createStatement();
r = st.executeQuery(sql);
System.out.println(st.executeQuery(sql));
} catch (SQLException ex) {
Logger.getLogger(Tmrptryone.class.getName()).log(Level.SEVERE, null, ex);
}
return r;
}
his method in the event of a button, with this method I want to print in the textfield the data I receive from the database but I got an error.
public void actualizatext() {
try {
ResultSet r = mrp.getmax();
if (r.next()) {
String ID = r.getString("Cantidad");
pruebamax.setText(ID);
}
} catch (SQLException ex) {
Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
Now, I don't know what pruebamax means but the SQL statement you used:
String sql = "SELECT COUNT(*) AS Cantidad FROM tbl_padre";
is specifically used to count the total number of records currently maintained within the specified database table (tbl_padre). The value from that count will be held in the specified temporary field named: Cantidad. When you Use the SQL COUNT statement you are not going to be returned a String data type value. You will be expected to try and acquire a Integer value.
It will not acquire a value from your table ID field as what it looks like you expect.
To properly retrieve the records count from your applied SQL string then it should be used in this fashion:
int count = 0;
try {
String sql = "SELECT COUNT(*) AS rCount FROM tbl_padre";
Statement st = cx.createStatement();
ResultSet r = st.executeQuery(sql);
while (r.next()) {
count = r.getInt("rCount");
}
r.close();
st.close();
// Close your DB connection as well if desired.
// yourConnection.close();
//To apply this value to your JTextField:
pruebamax.setText(String.valueOf(count));
System.out.println("Total number of records in the tbl_padre " +
" table is: " + count);
}
catch (SQLException ex) {
ex.printStackTrace();
}
Try not to use actual table field names for temporary field names.
If you want to be more specific with your count then your SQL statement must be more specific as well. For example, let's assume that we want to count the number of records maintained in our table where a field named Age contains a value which is greater than 30 years old, our sql statement would look like this:
String sql = "SELECT COUNT(*) AS rCount FROM tbl_padre WHERE Age > 30";
You will of course have noticed the use of the SQL WHERE clause.
I'm trying to store rows from a table into an array. I can get the first result and store that but I cannot seem to be able to store any of the other data.
This is the code I've written
try
{
test = "select * from Arsenal order by 'MatchNumber' ASC";
rs = st.executeQuery(test);
while (rs.next())
{
//This retrieves each row of Arsenal table and adds it to an array in the Team Results class.
matchno = rs.getString("MatchNumber");
hometeam = rs.getString("HomeTeam");
awayteam = rs.getString("AwayTeam");
homegoals = rs.getString("HomeGoals");
awaygoals = rs.getString("AwayGoals");
result = rs.getString("Result");
teams = (matchno + "," + hometeam + "," + awayteam + "," + homegoals + "," + awaygoals + "," + result); // Takes all the variables containging a single customers information and puts it into a string, seperated by commas.
TeamResults.add(matchno,hometeam,awayteam,homegoals,awaygoals,result);
}
}
Any idea where I'm going wrong?
Change the while-condition to hasNext() and use next() inside of the loop to move the database cursor forward.
Try to use this method bellow :
public void SelectData(String sqlcounter ,String sql){
try {
RsCounter=stmt.executeQuery(sqlcounter);
System.out.println(sqlcounter);
while(RsCounter.next()){
countrow=RsCounter.getInt("COUNTR");
System.out.println(countrow+"\n");
}
System.out.println(sql);
RsSelecting = stmt.executeQuery(sql);
data=new String[countrow][RsSelecting.getMetaData().getColumnCount()];
header= new String[RsSelecting.getMetaData().getColumnCount()];
i=0;
while(RsSelecting.next()){
for(j=0;j<RsSelecting.getMetaData().getColumnCount();j++){
data[i][j]=(RsSelecting.getString(j+1));
header[j]=RsSelecting.getMetaData().getColumnName(j+1);
System.out.print(data[i][j]+"\n");
}
i++;
}
i=j=0;
} catch (SQLException ex) {
ex.printStackTrace();
Logger.getLogger(Connect.class.getName()).log(Level.SEVERE, null, ex);
}
}
where
sqlcounter ="select COUNT(*) as COUNTR from Arsenal order by 'MatchNumber' ASC";
and
sql ="select * from Arsenal order by 'MatchNumber' ASC";
Verify the column names once. Sometimes ALIAS doesn't work out, I am not sure why.
Get the meta data from the result set:
ResultSetMetaData metaData = resultSet.getMetaData();
int size = metaData.getColumnCount();
for (int i = 0; i < size; i ++)
System.out.println(metaData.getColumnName(i);
Also just for performance, list out the column names instead of using * in the SELECT query. Also, you can take a look at com.sun.rowset.CachedRowSetImpl. It's used like:
CachedRowSetImpl crs = new CachedRowSetImpl();
crs.populate(resultSet);
I think it also implements CachedRowSet, but I am not entirely sure.