I have a Java program reading data from an Access database where the table is created dynamically each time, and the number of columns varies depending on the data populated.
The table has columns as shown below. Only columns RowID and StatusOfProcessing are fixed and will be at the end.
column1,column2,column3, ... columnN,RowID,StatusOfProcessing
Below is piece of code
String str = "SELECT TOP 50 * FROM Dynamic_table WHERE StatusOfProcessing='0'";
resultSet = stmt.executeQuery(str);
When reading data from the ResultSet, does it always have columns in the order listed above, or should I use
String str = "SELECT TOP 50 column1,column2,column3 .... columnN,RowID,StatusOfProcessing FROM Dynamic_table WHERE StatusOfProcessing='0'";
resultSet = stmt.executeQuery(str);
Can someone clarify?
SELECT * will normaly return columns in the order in which they were created, e.g., the order in which they appeared in the CREATE TABLE statement. However, bear in mind that in addition to retrieving the value of a column by its index, as in
int col1value = resultSet.getInt(1);
you can also retrieve the value in a given column by referring to its name, as in
int col1value = resultSet.getInt("column1");
Furthermore, if you need to see the actual order of the columns or verify the names and types of the columns in a ResultSet you can use a ResultSetMetaData object to get that information.
Related
I want to generate a SQL query where tables name is stored in the tables array.
and the corresponding columns name stored in a 2-D array.
example:-
Tables array
[T1,T2,T3]
Columns array
[
[C1,C2], // T1 columns
[C1,C2], // T2 columns
[C1,C2] // T3 columns
]
QUERY:-
select T1.C1,T2.C1,T3.C1 from T1
inner join T2 ON T2.C2=T1.C2;
inner join T3 ON T3.C2=T1.C2
select first column of every table in the array
if they have a match in the second column
[assuming every table has 2 columns]
I don't want to execute this query.
I just want to print it using JOOQ.
Can someone pls help me out on this.
The phrasing of your question gives room to some interpretation. I'm assuming you have these specific array types:
Table<?>[] tables = ...
Field<?>[][] fields = ...
I'm assuming that your requirement is to match all tables by common column names (i.e. names that are the same as the name of the second column of the first table), in order to join them. Since you do not specify what happens if consecutive tables don't have such a match, I'm assuming you'd like to default to excluding such tables, and their columns.
In any case, I guess this is more of a question about an idea on how to do dynamic SQL with jOOQ in general, not necessarily how to solve your particular problem.
In that case, write:
Field<?> match = fields[0][1];
List<Field<?>> select = new ArrayList<>();
Table<?> from = tables[0];
select.add(fields[0][0]);
for (int i = 1; i < fields.length && i < tables.length; i++) {
if (match.getName().equals(fields[i][1].getName())) {
select.add(fields[i][0]);
from = from.join(tables[i]).on(match.eq((Field) fields[i][1]));
}
}
ctx.select(select)
.from(from)
.fetch();
If your actual requirements are very different to these assumptions, you can still ask a new question.
there's column I want to retrieve and insert into another table
For example, below is first table I want to retrieve values
Table1
Records
1 ABC Singapore
2 DEF Vietnam
I retrieve above column value from Table1, then insert into another table as below
Table 2
ID Name Country
1 ABC Singapore
2 DEF Vietname
Currently, I can do with java, I first retrieve records then split the values and insert. However, I want to do it by batch or pagination for better performance when Table1 got million of records to retrieve and insert those million records into Table2.
Any pointer to show me how to use pagination in my case would be appreciated.
I"m use MSSQL 2008
If you need to do that in code (and not in SQL which should be easier even with multiple delimiters), what you probably want to use would be batched inserts with proper batch size combined with a good fetch-size on your select:
//Prepare statements first
try(PreparedStatement select = con.prepareStatement("SELECT * FROM SOURCE_TABLE");
PreparedStatement insert = con.prepareStatement("INSERT INTO TARGET_TABLE(col1, col2, col3) VALUES (?,?,?)")) {
//Define Parameters for SELECT
select.setFetchDirection(ResultSet.FETCH_FORWARD);
select.setFetchSize(10000);
int rowCnt = 0;
try(ResultSet rs = select.executeQuery()) {
while(rs.next()) {
String row = rs.getString(1);
String[] split = row.split(" |\\$|\\*"); //However you want to do that
//Todo: Error handling for array length
//Todo: Type-Conversions, if target data is not a string type
insert.setString(1, split[0]);
insert.setString(2, split[1]);
insert.setString(3, split[2]);
insert.addBatch();
//Submit insert in batches of a good size:
if(++rowCnt % 10000 == 0) {
int[] success = insert.executeBatch();
//Todo: Check if that worked.
}
}
//Handle remaining inserts
int[] success = insert.executeBatch();
//Todo: Check if that worked.
}
} catch(SQLException e) {
//Handle your Exceptions
}
On calculating on "good" fetch and batch sizes you'll want to consider some parameters:
Fetchsize impacts memory consumption in your client. If you have enough of that you can make it big.
Committing an insert of millions of rows will take some time. Depending on your requirements you might want to commit the insert transaction every once in a while (every 250.000 inserts?)
Think about your transaction isolation: Make sure auto-commit is turned off as committing each insert will make most of the batching gains go away.
I have a rather sticky situation:
I have been tasked with designing an application that will read the contents of a table from a MySQL database into a two-dimensional string array, scalable to 100.
The schema for the table is:
id = INT(11)
Username = VARCHAR(100)
Password = VARCHAR(45)
UserType = VARCHAR(10)
Full Name = VARCHAR(100)
Age = INT(11)
DOB = DATE
Location = VARCHAR(100)
Record_Created = DATETIME
The issue is that I cannot read this to a file and then to the application for security reasons (contains actual admin account information). Can anyone think of an efficient way of doing this?
.... into a two-dimensional string array, scalable to 100.
I take it that you mean the array can have up to 100 elements.
If so, then one solution is to preallocate an array of size 100 x 9, then query and read the table rows and populate the array.
A second solution is to query, read the table rows, populate a list-of-arrays, and use List.toArray to extract the list contents into a 2-D array.
A final solution is to use select ... count to find the number of rows, and use that to allocate a 2-D array with the correct size. Then proceed as per the first solution.
However, using a 2-D array is a bad idea from an O-O design perspective. Instead, you should declare a class with a field for each of the 9 columns, and then represent the table contents as an array or list of that class.
I implemented the following design for my above question:
public static String[][] Table() throws SQLException
{
String[][] Table = null;
table = conn.createStatement();
String sql = "select * from usersTable";
ResultSet rs = table.executeQuery(sql);
rs.last();
int rowNumb = rs.getRow();
ResultSetMetaData rsmd = rs.getMetaData();
int columnS = rsmd.getColumnCount();
rs.beforeFirst();
dbTable= new String[rowNumb][columnS];
int i=0;
while(rs.next() && i<rowNumb && rowNumb<100)
{
for(int j=0;j<columnS;j++)
{
Table[i][j] = rs.getString(j+1);
}
i++;
}
return Table;
}
I need to get the latest entry from my database, but not the autoincrement.
This function is in my databasehandler:
public int getLatestRouteNumber()
{
int number = 0;
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT MAX("+ KEY_ROUTENUMBER + ") FROM " + TABLE_LOCATIONS;
Cursor c = db.rawQuery(query, null);
if (c.moveToFirst() && c != null) {
number = c.getInt(3);
}
return number;
}
it craches at the line where "number = c.getInt(3).
The third column in my database exists and has data in it.
The error I'm gettin is "Couldn't read row 0, col 3 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it." I only need one value in the entire database, not even an entire row.
You have only one column in cursor but trying to get value of 3rd column... Tat is the error
Change it to getInt(0);
The returned result-set has nothing to do with table columns in your case. You should use
number = c.getInt(0);
Your resultset contains just one column and one row, basically a scalar value, it doesn't matter how many columns you have in your table, what you should consider here is the value you obtain from your query In your case just one value. Use
getInt(0)
have you tried something like this :
String query = "SELECT MAX("+ KEY_ROUTENUMBER + ") as my_max FROM " + TABLE_LOCATIONS;
And :
columnIndex = c.getColumnIndexOrThrow("my_max");
number = c.getInt(columnIndex );
That's better than using indexes, indexes may be wrong if the raw query changes.
getInt (3) returns the value of the 3rd column returned by the query. Your query only had 1 column.
Change getInt (3) to getInt (0)
"c.getInt(3);" does not get the value from the column in your table, it gets it from the column in your cursor.
And you only selected one column into your cursor.
So I believe it should be "c.getInt(1);"
I have a SELECT query which combining three tables. I want to add them to a Jtable by separating the MYSQL tables. I just want to know how can I identify the table name in a Resultset?
resultLoad("SELECT sqNum,RegDate,JobNo,DecName,NoOfLines,EntryType,EntrySubType,EntrySubType2,Amount,Status FROM paysheet WHERE TypeBy='" + cmbStaff.getSelectedItem().toString() + "' AND CommissionStatus='no' UNION SELECT sqNum,RegDate,JobNo,DecName,NoOfLines,EntryType,EntrySubType,EntrySubType2,Amount,Status FROM creditsheet WHERE TypeBy='" + cmbStaff.getSelectedItem().toString() + "' AND CommissionStatus='no' ORDER BY RegDate UNION SELECT sqNumber,date,JobNumber,DecName,noOfLines,type,type,type,CommissionAmount,status FROM newjobsheet WHERE TypeBy='" + cmbStaff.getSelectedItem().toString() + "' AND CommissionStatus='no' ORDER BY RegDate");
private void resultLoad(String loadQuery) {
try {
Connection c = DB.myConnection();
Statement s = c.createStatement();
ResultSet r = s.executeQuery(loadQuery);
while (r.next()) {
Vector v = new Vector();
v.addElement(r.getString("sqNum"));
v.addElement(r.getString("RegDate"));
v.addElement(r.getString("JobNo"));
v.addElement(r.getString("DecName"));
v.addElement(r.getString("NoOfLines"));
v.addElement(r.getString("EntryType") + " - " + r.getString("EntrySubType") + " - " + r.getString("EntrySubType2"));
v.addElement(r.getString("Amount"));
v.addElement(r.getString("Status"));
tm.addRow(v);
totalComAmount = totalComAmount + Integer.parseInt(r.getString("Amount"));
}
} catch (Exception e) {
// e.printStackTrace();
JOptionPane.showMessageDialog(this, e, "Error!", JOptionPane.ERROR_MESSAGE);
}
}
I want to add to the Jtable like this by sorting the dates. But the three tables containing different columns.
From your result set, you can get ResultSetMetaData. It looks like this:
rs.getMetaData().getTableName(int Column);
"I want to add them to a table by separating the tables."
Not sure what you mean by that, but:
"I just want to know how can I identify the table name in a Resultset?"
the answer is no, not unless you rewrite the query so that it does it for you.
A SELECT statement yields a new (virtual) table - any columns it delivers are technically columns of that new virtual table. The result does not remember the origin of those columns
However, you can write the query so as to give every expression in the SELECT list a column alias that allows you to identify the origin. For instance, you could do:
SELECT table1.column1 AS table1_column1
, table1.column2 AS table1_column2
, ...
, table2.column1 AS table2_column1
, ...
FROM table1 INNER JOIN table2 ON ... etc
If the underscore is not suitable as a separator for your purpose, then you could consider to quote the aliases and pick whatever character as separator you like, including a dot:
SELECT table1.column1 AS `table1.column1`
, ....
etc.
UPDATE:
I just noticed your query is a UNION over several tables. Obviously this method won't work in that case. I think your best bet is still to rewrite the query so that it reads:
SELECT 'paysheet' as table_name, ...other columns...
FROM paysheet
UNION
SELECT 'creditsheet', ...other columns...
...
It seems to me like you want to SELECT data from three separate tables and have it returned in one query as one ResultSet, then you want to separate the results back out into individual tables.
This is completely counter intuitive.
If you want to have your results separated so that you are able to look at each table's results separately, your best bet is to perform 3 different SELECT queries. Basically, what you are asking it to combine 3 things and then separate them again in one pass. Don't do this; if you leave them uncombined in the first place, separating them back out won't be an issue for you.