I have a SQLite database with 44 Columns and 700 rows. I created a user interface with Java ( I have two textFields and a Button) to search all columns with a specific value in first textField and update it with another value in second textField.
The problem is I don't know which column has the entered value in first textField, that's why I cant use directly "Update table_name SET column_name ..." Statement.
What I tried is ;
"Select * FROM table_name WHERE '%" + TextField.getText() + "%';
But it didn't work.
Can you help me to build right query?
You could look into FTS tables as CL mentioned but another way is to create an easier way to query every column. You would create a function to loop through every column to make its where clause and join them all together using OR. One way to automate this and save writing all 44 column names is to query the database for all the column names and use that later for the query.
public String columnsLike(String like, String... cols) {
return columnsLike(like, Arrays.asList(cols));
}
public String columnsLike(String like, List<String> cols) {
List<String> where = new ArrayList<>();
for(String column : cols) {
where.add(column+" LIKE '"+like+"'");
}
return where.stream().collect(Collectors.joining(" OR "));
}
public List<String> getColumns(String table) {
ResultSet rs = statement.executeQuery("SELECT * FROM "+table);
ResultSetMetaData rsmd = rs.getMetaData();
List<String> columns = new ArrayList<String>();
for (int i = 1; i < rsmd.getColumnCount(); ++i) { columns.add(rsmd.getColumnName(i)); }
return columns;
}
String query = "SELECT * FROM table_name WHERE "+columnsLike('%'+textField.getText()+'%', "column1", "column2", "column3", "column4", "column5");
// Result:
// SELECT * FROM table_name WHERE column1 LIKE '%hello%' OR column2 LIKE '%hello%' OR column3 LIKE '%hello%' OR column4 LIKE '%hello%' OR column5 LIKE '%hello%'
// However you could save time from writing out every column and load them once into an array.
List<String> columns = getColumns("table_name");
// Then call columnsLike('%'+textField.getText()+'%', columns);
To go about updating the values in the row that matched the select query you will have to go through the ResultSet rows and check them again in order to update that specific column. However, since I do not know if all of your columns are Strings I am using getObject() instead of getString() but you can change that if all of your columns are strings. Also, without knowing the data, multiple columns could match so this will update as many matches as it finds.
public void updateColumns(String tableName, List<String> cols, ResultSet rs, String like, String newValue) {
PreparedStatement ps = conn.prepareStatement("UPDATE "+tableName+" SET "+column+" = ? WHERE "+column+" = ? ");
while(rs.next()) {
for(String column : cols) {
String value;
if((value = rs.getObject(column).toString()).matches(".*"+like+".*")) {
ps.setString(1, newValue);
ps.setString(2, value);
ps.addBatch();
}
}
}
ps.executeBatch();
ps.close();
// rs.close();
}
// updateColumns("table_name", columns, resultSet, textField.getText(), textField2.getText());
Related
I want to add values in a table that has dynamic columns.
I managed to create a table with dynamic columns but I cannot figure out how to insert data.
//Create Table
sql = "CREATE TABLE MyDB.myTable" +
"(level INTEGER(255) )";
int columnNumber = 5; //Number of columns
//Add columns
for (i=0;i<columnNumber;i++){
String columnName = "Level_" +i:
String sql = "ALTER TABLE MyDB.myTable ADD " + columnName + " INTEGER(30)";
}
//Insert Data
//How to insert data dynamically, without knowing the number of columns?
You can also use database metadata to get the column names. This has the advantage that you even don't need to know the column names, rather they are retrieved dynamically in your code.
public static List<String> getColumns(String tableName, String schemaName) throws SQLException{
ResultSet rs=null;
ResultSetMetaData rsmd=null;
PreparedStatement stmt=null;
List<String> columnNames =null;
String qualifiedName = (schemaName!=null&&!schemaName.isEmpty())?(schemaName+"."+tableName):tableName;
try{
stmt=conn.prepareStatement("select * from "+qualifiedName+" where 0=1");
rs=stmt.executeQuery();//you'll get an empty ResultSet but you'll still get the metadata
rsmd=rs.getMetaData();
columnNames = new ArrayList<String>();
for(int i=1;i<=rsmd.getColumnCount();i++)
columnNames.add(rsmd.getColumnLabel(i));
}catch(SQLException e){
throw e;//or log it
}
finally{
if(rs!=null)
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
throw e
}
if(stmt!=null)
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
throw e
}
}
return columnNames;
}
Once you have the column names, you can use it as you normally would (List.size() would of course give the number of columns).
UPDATE:
//I will assume that your values (data to be inserted) is a List of Object types and that it is already populated
List<Object> data = new ArrayList<>();
//you will populate this list
//getting the column names
List<String> columnNames = getColumns("MyTable", "MyDB");
String insertColumns = "";
String insertValues = "";
if(columnNames != null && columnNames.size() > 0){
insertColumns += columnNames.get(0);
insertValues += "?";
}
for(int i = 1; i < columnNames.size();i++){
insertColumns += ", " + columnNames.get(i) ;
insertValues += "?";
}
String insertSql = "INSERT INTO MyDB.MyTable (" + insertColumns + ") values(" + insertValues + ")";
try{
PrepareStatement ps = conn.prepareStatement(insertSql);
for(Object o : data){
ps.setObject(o); //you must pass objects of correct type
}
ps.execute(); //this inserts your data
}catch(SQLException sqle){
//do something with it
}
This code assume that you pass objects of correct types to PreparedStatement.setObject(Object o) method. It's also possible to retrieve column types using metadatabase information and then use that info to enforce type checking but that would make your code much more complicated
If you know the number of columns you want to insert, you can make your insert query same way you made your CREATE TABLE. Explicitly name the columns you want to add your data into, and make sure the columns you leave empty are allowed to be empty (NULL or default=0)
INSERT INTO MyDB.myTable (Level_1, Level_2, ...) VALUES (Val_1, Val_2, ...);
The alternative approach would be to store each inserted value in a separate row. In that way you don't vhave to change the number of columns in your table.
You need a table where you have a ID for every group of values:
- ID
- Level
- Value
You could have a separate table where you can register each ID:
- ID (bigInt, auto increment, primary key)
- info field
- timestamp
Now, for every set of data you want to insert, first insert need a Unique ID. If you use the second table, inserting a new row would give you a new ID:
INSERT INTO register_table (ID, info, timestamp) VALUES (NULL, 'some info', NOW());
This will give you a new ID (last_inserted_id).
With this ID now insert all values in the other table:
for(i=0i<columnNumber;i++){
"INSERT INTO _table (ID, Level, _Value) VALUES ("+ the_ID +", "+ i +", "+ the_VALUE +");";
}
If you want to fetch the data:
"SELECT Level, _Value FROM _table WHERE ID="+ the_ID +" ORDER BY Level;";
I have a dynamic number of data values in an array fetched from an HTML form.
Now I want to update my table with these data.
The column names are column1 , column2 ... and so on;
I have data in the array[] and number of columns to update in unumber
I am using this code but its not working.
P.S: I am new to coding so it might be naive.
for(int i=1; i<=unumber; i++)
{
String username = "someuser";
String column = "column" + Integer.toString(i);
PreparedStatement pr = null;
String query1 = "update table1 set (?) = (?) where username = (?)";
pr = con.prepareStatement(query1);
pr.setString(1, column);
pr.setString(2, array[i]);
pr.setString(3, someuser);
int s = pr.executeUpdate();
}
AFAIK, you can't use "prepared statements" for this. You can resolve it by performing the insertion in the query yourself:
String query1 = "update table1 set "+column+" = ? where username = ?";
pr = con.prepareStatement(query1);
pr.setString(1, array[i]);
pr.setString(2, someuser);
But be aware of sql injection. You better check whether the possible values of column can't be altered. Validate all input that leads to determining the column name.
Make sure a user can't specify the column his/herself: otherwise one could for instance set the column to password and set a password for some user. And then login with that password. Or one could try to set the column to '; drop table foo; select * where x
PreparedStatments can only bind values, not syntactic elements or object names, like columns, so this approach won't work. You'll have to fall back to string manipulation:
for(int i=0; i<unumber; i++) {
String username = "someuser";
String column = "column" + Integer.toString(i);;
PreparedStatement pr = null;
String query1 = "update table1 set " + column + " = (?) where username = (?)";
pr = con.prepareStatement(query1);
pr.setString(1, column);
pr.setString(2, someuser);
int s = pr.executeUpdate();
}
Moreover, since you're updating several columns with the same where clause, you could loop over the columns and construct just one update statement. It will force you to have two loops (one for constructing the query and one for binding the values once the query is prepared), but it should still be considerably faster, as you're accessing the database only once instead of N times:
String username = "someuser";
StringBuilder sql = new StringBuilder("update table1 set ");
for(int i=0; i < unumber; i++) {
sql.append("column")
.append(i).
.append(" = ?");
if (i != (unumber - 1)) {
sql.append(", ");
}
}
sql.append("where username = (?)");
PreparedStatement pr = con.prepareStatement(sql.toString());
for(int i = 0; i < unumber; i++) {
pr.setString(i, array[i]);
}
pr.setString(unumber, someuser);
int s = pr.executeUpdate();
I have this database table named Store_Data and I show three columns in the JTable.
Here are the columns:
NUMBERS
AMOUNT
DATE
How do I show the other columns in the jtable? The other columns are missing
I managed to obtain combined values using this SQL command, "SELECT NUMBERS, SUM(AMOUNT) FROM Store_Data GROUP BY NUMBERS", and I managed show it in the JTable.
However, In the JTable I only see the column NUMBERS and another column showing all the sum of the AMOUNT values. I don't see the other columns in the Jtable.
Here is my code,
private JTable showRecords(Connection con)
{
try
{
column.clear();
data.clear();
_stmt = con.createStatement();
//String getColumn = "SELECT * FROM APP.NYPMTRIPLESTRAIGHT";
/*this is only a test*/
String test = "SELECT NUMBERS, SUM(AMOUNT) FROM Store_Data GROUP BY NUMBERS";
ResultSet rs = _stmt.executeQuery(test);
//this will collect the data from the database
ResultSetMetaData metaData = rs.getMetaData();
//this will count all the columns from
int column_count = metaData.getColumnCount();
for(int j = 1; j <= column_count; j++)
{
column.add(metaData.getColumnName(j));
}
while(rs.next())
{
Vector<Object> vector = new Vector<Object>();
for(int i = 1; i <= column_count; i++)
{
vector.add(rs.getObject(i));
}
data.add(vector);
}
_records = new JTable(data, column);
return _records;
} catch (SQLException ex)
{
JOptionPane.showMessageDialog(null, ex.getMessage());
}
return _records;
}
NOTE: I know it is wrong to use Vector. I am only using it for testing.
Your query sums all the values of AMOUNT and displays the sum using a Group by clause.
Group by will group similar values into one entity based on the functions used. ["sum" in your case].
You need to get the numbers and amount from your database simply
SELECT NUMBERS, AMOUNT FROM APP.NYPMTRIPLESTRAIGHT;
then display the resultset data in your JTable.
Try this:
SELECT
t1.NUMBERS,
CONCAT(YEAR(T1.DATE) , '-' , MONTH(t1.DATE) , '-' ,DAY(t1.DATE)) as DATE,
SUM(AMOUNT) AS AMOUNT
FROM table1 t1
GROUP BY 1, 2
And here you have the sqlfiddle
I have a query in which I am using Cursors in Select clause along with some other columns Values.I wanted to iterate through its result via ResultSet in Java.But couldn't find a way to get the Cusror from the result set.Is it possible to do so?Can anyone help me?
For eg
select name, roll_no,
cursor (select subj1
from Subject
where id = 'abc'
) as cusr1
from student
Here would be a generic way to read columns from a ResultSet.
while (resultSet.next()) { //Read every row
int columnCount = resultSet.getMetaData().getColumnCount();
for (int column = 1; column <= columnCount; column++) { //Read every column
String columnName = resultSet.getMetaData().getColumnName(column);
Object value = resultSet.getObject(columnName);
if (value != null) {
doSomething(columnName, value);
}
}
}
I assume you are using an Oracle DB.
I also assume Java 7 or higher (try with resources).
You are using a Cursor Expression in your SQL.
The Oracle JDBC Driver returns a java.sql.Resultset object when you call Resultset.getObject(column number|column label) for a Cursor Expression column.
So it is safe to cast:
try (Resultset innerResultset = (Resultset) outerResultset.getObject(column number/label)) {
while(innerResultset.next()) {
...
}
One comment: In many cases, for example when creating "master-detail" queries, you use a correlated Cursor Expression, meaning there is a join on a table that appears in the outer query.
I am working on a java project
I am using jdk 1.6
I am want to add data from database in jtable
I have achieved this by using DefaulTableModel
and I got the column names by using ResultSetMetadata
but the problem is
**I am getting a extra column name A at the 0th index of jtable
I want to remove this column
it looks like this
A | deptno
I only need deptno
**
the code used for creating this model is
private void updateTable() throws Exception {
String sqlrow = "Select count(*) from emp";
rs= db.sta.executeQuery(sqlrow);
rs.next();
int rows=rs.getInt(1);
System.out.println(""+rows);
String sqldata = "SELECT deptno FROM emp";
rs =db.sta.executeQuery(sqldata);
rsMD = rs.getMetaData();
numberOfColumns = rsMD.getColumnCount();
ColumnNames = new String[numberOfColumns+1];
System.out.println(""+numberOfColumns);
for(int i=1;i<=numberOfColumns;i++)
{
String colName=rsMD.getColumnName(i);
ColumnNames[i] = colName;
System.out.println(""+ColumnNames[i]);
}
//Cj is a method which takes sqlQuery , rows, column
Object[][] rowData=CJ(sqldata,rows,numberOfColumns);
//jt is table name
jt.setModel(new DefaultTableModel(rowData,ColumnNames));
}
// code for cj()
public Object[][] CJ(String sql,int rows,int cols)
{
Object[][] obj=new Object[rows][cols+1];
ResultSet rs=null;
try{
rs= db.sta.executeQuery(sql);
int c=0;
while(rs.next())
{
for(int i=1;i<=cols;i++)
{
obj[c][i]=rs.getString(i);
}
c++;
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
return obj;
}
I am using this code on
button click
updateTable();
jsp = new JScrollPane(jt); // jt is Jtable
jp.add(jsp); //jp is jpanel
please help me out
Not following the naming convention makes it hard to read, but I would suggest to take a closer look at the following piece of code
numberOfColumns = rsMD.getColumnCount();
ColumnNames = new String[numberOfColumns+1];
System.out.println(""+numberOfColumns);
for(int i=1;i<=numberOfColumns;i++)
{
String colName=rsMD.getColumnName(i);
ColumnNames[i] = colName;
System.out.println(""+ColumnNames[i]);
}
Here you explicitly use more column names then numberOfColumns. Idem for your CJ method, where you start at index 1.
Just start all those for loops at index 0, make the arrays one shorter and everything should work