I have two result sets
source rs;
target rs1;
I am storing metadata of a table in both the result set using below
DatabaseMetaData dbmd=con.getMetaData();
ResultSet rs=dbmd.getColumns(null, null, tableName, null);
table is having meta data as below.
name varchar 10;
age int 2;
salary double;
Please can anyone help me in this. I need to compare if both tables are having same column name and data type along with column length.
please also suggest if there is any better method.
Related
I am using JDBC and PostgreSQL as database, I was trying to create a logic in such a way that we can fetch all the data from a table, whatever table name user gives in the input it should get fetched, but the issue here is, I don't know how to do that.
Whenever we used to fetch table data from the database we are required to specify the the type of data we are getting on every index while we use ResultSet.
How to overcome from this hardcoded need of providing this metadata and make our code more general for any table with any number of columns and with any type
My code:
Statement sttm = con1.createStatement();
System.out.println("Enter table name (usertable)");
String name = sc.next();
String tableData="";
String qu = "select * from "+name;
ResultSet rs =sttm.executeQuery(qu);
while(rs.next()) {
// here we need to define the type by writing .getInt or getString
tableData = rs.getInt(1)+":"+rs.getString(2)+":"+rs.getInt(3);
System.out.println(tableData);
}
System.out.println("*********---------***********-----------**********");
sttm.close();
Anyone please suggest me some way to do it.
You can use ResultSet.getObject(int). getObject will automatically retrieve the data in the most appropriate Java type for the SQL datatype of the column.
To retrieve the number of columns, you can use ResultSet.getMetaData(), and then use ResultSetMetaData.getColumnCount() to retrieve the number of columns.
In short, to print all columns of all rows, you can do something like:
try (ResultSet rs = stmt.executeQuery(qu)) {
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
while (rs.next()) {
StringBuilder tableData = new StringBuilder();
for (int colIdx = 1; colIdx <= columnCount; colIdx++) {
tableData.append(rs.getObject(colIdx));
if (colIdx != columnCount) {
tableData.append(':');
}
}
System.out.println(TableData);
}
}
You can also use ResultSetMetaData to get more information on the columns of the result set, for example if you need specific handling for certain types of columns. You can use getColumnType to get the java.sql.Types value of the column, or getColumnTypeName to get the type name in the database, or getColumnClassName to get the name of the class returned by ResultSet.getObject(int/String), etc.
However, as Sorin pointed out in the comments, accepting user input and concatenating it into a query string like you're currently doing, makes you vulnerable to SQL injection. Unfortunately, it is not possible to parameterize object names, but you can mitigate this risk somewhat by 1) checking the table against the database metadata (e.g. DatabaseMetaData.getTables), and 2) using Statement.enquoteIdentifier (though this won't necessarily protect you against all forms of injection).
If you want to print data of any table from a database then check my github project over CRUD java MySQL
https://github.com/gptshubham595/jdbc_mysql_CRUD-JAVA-
These are implemented
This question may be very easy, but I´m not exactly sure, how to do this.
I want to store the return value from my SQL-statement in a variable.
int i;
String name = "Testuser";
First i create my var. Now I want to store the value, which is saved in my Database (named Data) in a field called "money" , with the key "Testuser" into my variable i.
Now you have already the instance of statement you can do something like that
int i;
ResultSet resultat = null;
resultat = statement.executeQuery("SELECT money FROM data WHERE id=1;");//for example the value of the field money in the row who has id=1
if(resultat.next()){ // you check if the query returned a value
i=resultat.getInt("money"); // the name of the column
}
I have two sqlite tables in a specific database. I want to add the same data to both tables but on the second table I want to also store the ID of that entry in the first table.
What I do is add the entry ('Name', 'Description') to the first table then query to get the 'ID2' value then add the entry and the ID2 number into my second table after (Put ID2 in as ID3). I always rawquery to get my last entry's 'ID2' column value.
I have this working in the sense that it doesnt crash and does add a value to my second table BUT its isnt adding the value but instead some sort of reference which I do not understand so cant look up.
I would like a solution to get the the last 'ID2' value of my first table and insert it into my second table in 'ID3' column ALSO I would like an explanation of why what I have below is wrong.
Please reference my Java code below and screenshots of my two databases (the second showing the reference code not the value I want)
Thank you so much.
public boolean insetTheme(String name2,String Description){
SQLiteDatabase Mydb =this.getWritableDatabase();
ContentValues newThingAdd = new ContentValues();
newThingAdd.put(COL2_ALLTHEMES,name2);
newThingAdd.put(COL3_ALLTHEMES,Description);
long result = Mydb.insertOrThrow(TABLE_ALLTHEMES,null,newThingAdd);
Cursor res = Mydb.rawQuery("select * from "+TABLE_ALLTHEMES + " where 'ID2'" ,null);
//res.moveToLast();
if (res != null) {
res.move(-1);
}
ContentValues newThingAdd123 = new ContentValues();
newThingAdd123.put(COL2_CURRENTTHEMES,name2);
newThingAdd123.put(COL3_CURRENTTHEMES,Description);
newThingAdd123.put("ID3",res.toString());
long result2 = Mydb.insertOrThrow(TABLE_CURRENTTHEMES,null,newThingAdd123);
if ((result==-1)&(result2==-1))
return false;
else
return true;
}
First Table
Second Table
res is a Cursor so calling toString() on it won't give you what you want.
You need to use res.getString(0) or similar with the specific method based on what type the value is (String, int, boolean etc) and the number being the column number, for example, if the value you want is the third column that would be returned in the query, use res.getString(2) to get the value.
If I made a query like this:
Cursor cursor = Mydb.rawQuery("SELECT * FROM table_1");
and table_1 had 3 columns:
id, name, date
if I wanted the name, I would use
String name = cursor.getString(1);
Hopefully this is what you were after.
I get this error when i was inserting some rows to database.
Code
public class InsertRowData {
public static void main(String[] args)throws ClassNotFoundException, SQLException{
Connection con = (Connection) DriverManager
.getConnection("jdbc:oracle:thin:#localhost:1521:ORCL" , "system" , "system");
Statement statement = con.createStatement();
String dmlinsert = "insert into student(111,manoj,rawatrulz09)";
int rowseffected = statement.executeUpdate(dmlinsert);
System.out.println("no of rows effected" + rowseffected);
}
}
After searching in google I found the solution to remove single quotes from the column but still getting the same error.
This is a bad approach to insert any data into the Table.
String dmlinsert="insert into student(111,manoj,rawatrulz09)"
first of all, your query missing a syntax Values.
when columns are not mentioned while inserting, values must contain same amount of data and respectively.
But when inserting a data the best practice is to mention columns, so that if in later time you make any change to the table in database, your insert query stays stable.
for e.g:
insert into student(id, name, email) values(111,'manoj','rawatrulz09').
Now, if in future you will add a column to this table, your insert query will still work as it has mentioned columns, but if you won't mention any columns then your code will start giving error when executed no of values don't match given to the table etc... Good luck!
anyway, answer for your insert query:
insert into student values(111,'manoj','rawatrulz09')
Imagine I have a query like
SELECT * from table1 a, table2 b where (WHATEVER)
Maybe both tables have the same column name. So I though it would be nice to access the data via
resultSet.getString("a.columnName");
resultSet.getString("b.columnName");
But this backfires on me and I get nothing. I read the API, but they don't really talk about this case. Is such a feature vendor dependent?
JDBC will simply name the columns by what is specified in the query - it doesn't know about table names etc.
You have two options:
Option 1: Name the columns differently in the query, ie
SELECT
a.columnName as columnNameA,
b.columnName as columnNameB,
...
from table1 a, table2 b where (WHATEVER)
then in your java code refer to the column aliases:
resultSet.getString("columnNameA");
resultSet.getString("columnNameB");
Option 2: Refer to the column position in your call to the JDBC API:
resultSet.getString(1);
resultSet.getString(2);
Note that the JDBC API uses one-based indexes - ie they count from 1 (not from 0 like java indexes), so use 1 for the first column, 2 for the second column, etc
I would recommend option 1, because it's safer to refer to named columns: Someone may change the order of the columns in the query and it would silently break your code (you would be accessing the wrong column but would not know), but if they change the columns names, you'll at least get a "no such column" exception at runtime.
ResultSetMetadata.getColumnLabel() is what you need
(edit)
sample example, as stated by bharal in comment
SELECT * from table1 a, table2 b where (WHATEVER)
ResultSetMetaData rsmd = rset.getMetaData();
rsmd.getColumnLabel(1);
Use column aliases like:
SELECT A.ID 'A_ID', B.ID 'B_ID' FROM TABLE1 AS A, TABLE2 AS B...
And specify all the columns you are retrieving (is a good practice).
If you are using MySQL just add
&useOldAliasMetadataBehavior=true
to your connectionString.
Afterwards you can use this little Helper:
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class ResultSetHelper {
private final Map<String, Integer> columnMap;
public ResultSetHelper(ResultSet rs) throws SQLException {
this.columnMap = new HashMap<>();
ResultSetMetaData md = rs.getMetaData();
int columnCount = md.getColumnCount();
for (int index = 1; index <= columnCount; index++) {
String columnName = md.getColumnLabel(index);
if (!columnMap.containsKey(columnName)) {
columnMap.put(columnName, index);
}
String tableAlias = md.getTableName(index);
if (tableAlias != null && !tableAlias.trim().isEmpty()) {
columnMap.put(tableAlias + "." + columnName, index);
}
}
}
public Integer getColumnIndex(String columnName) {
return columnMap.get(columnName);
}
public Integer getColumnIndex(String tableAlias, String columnName) {
return columnMap.get(tableAlias + "." + columnName);
}
}
Ok, it seems there's no method like resultSet.getString("a.columnName");
and you have to alias your columns at sql level,
but inasmuch as there's a getTableName(iCol) method I hope guys at
java.sql.ResultSet add such a feature.
You can use alias on SQL level.
Then you retrieve data by indexes. (But this approach will make maintenance a real nightmare)
SELECT a.column, b.column FROM table1 a, table2 b
String value = rs.getString(1);
One idea I had is to use the getTableName(iCol) to grab the table names for the duplicately-named columns, then wrap a hash of your own keys (with the table name prefix) that would point you to the correct column index, and reference your column-values that way. This would require an initial loop through the meta data at the beginning to set up. The only issue I see with this is that you are aliasing the table names as well. I've yet to find a way of getting those table name aliases from jdbc without managing it yourself when you build the sql statement. This solution would depend on what the syntactical pay-off would be to you.
Change your sql into
SELECT a.*, b.* from table1 a, table2 b where (WHATEVER)
than you can read from resulset by table alias
resultSet.getString("a.columnName");
resultSet.getString("b.columnName");