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;";
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'm inserting multiple rows into a table using a single insert statement. The table has an auto increment field as the primary key.
Like so: INSERT INTO MyTable VALUES (?,?,?,?),(?,?,?,?),(?,?,?,?),(?,?,?,?)
StringJoiner sj = new StringJoiner(",");
for(int i=0;i<salesmen.size();i++)
sj.add("(?,?,?,?)");
sql.append("INSERT INTO MyTable ");
sql.append("VALUES ");
sql.append(sj.toString());
try(PreparedStatement statement = connection.prepareStatement(sql.toString(),Statement.RETURN_GENERATED_KEYS)){
int i = 1;
for(Salesman salesman : salesmen){
statement.setDate(i++, DateUtil.toSqlDate(date));
statement.setString(i++, salesman.getName());
statement.setInt(i++, salesman.getWeeklyTargetCustomerId());
statement.setInt(i++, salesman.getCycle());
}
statement.executeUpdate();
ResultSet generatedKeys = statement.getGeneratedKeys();
while(generatedKeys.next()) {
log.info("generated key: " + generatedKeys.getLong(1)); //only prints 1 id
}
}
catch(SQLException e){
log.info("(!!) SQL Exception in Execution: " + e.getMessage());
log.info("\n\n" + sql.toString() + "\n");
}
When i call getGeneratedKeys(), it returns a ResultSet with only the id of the last row inserted, and not all of the rows. If i insert 50 rows, how do i obtain a resultset with 50 generated keys?
Although it's an old question, I hope it helps someone.
PreparedStatement pre = connection.prepareStatement("SQL", PreparedStatement.RETURN_GENERATED_KEYS);
for(Salesman salesman: salesmen) {
pre.setString(i++, ...);
pre.setString(i++, ...);
....
pre.addBatch(); // Add this
}
pre.executeBatch(); // Add this
ResultSet rs = pre.getGeneratedKeys();
while(rs.next()) {
int id = rs.getInt(1); // This should contain the id of the inserts in order.
}
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.
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());
The SQL DB has 110 tables and each table is having different column names. I have to loop through each table and fetch the data, so that I can write into a XML file.
For this, I created a new table called "MasterList" which holds all the 110 table names.
try{
// Connection for SQL Server.
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url = "jdbc:sqlserver://"+strDBServer+":1433;DatabaseName="
+ strDBName + ";" +
"User="+strDBUser+";Password="+strDBPassword+";";
Connection conn = DriverManager.getConnection(url);
if (conn != null) {
System.out.println("Connection Successful!");
}
//XML Transform
TransformerFactory tFactory = TransformerFactory.newInstance();
//Create a Statement object
Statement sql_stmt = conn.createStatement();
//Get List of all the tables present from Master table.
ResultSet rs = sql_stmt.executeQuery("SELECT TableName, Order FROM "
+ strDBName + ".[dbo].Master");
while (rs.next())
{
//Create a Statement object
Statement sql_stmt_1 = conn.createStatement();
String strTableName=rs.getString(1).trim();
int intOrder = rs.getInt(2);
hsMapTablesFromDB.put(strTableName,intOrder);
System.out.println("Hashmap --> " + hsMapTablesFromDB);
ResultSet rs_1 = sql_stmt_1.executeQuery("SELECT Name, LevelOfExistence, UniqueId FROM "
+ strDBName + ".[dbo]." + strTableName);
String strName = rs_1.getString(1).trim();
String strUnique = rs_1.getString(3).trim();
hsMapDataFromIndTable.put(strName,strUnique);
System.out.println("hsMapDataFromIndTable" + hsMapDataFromIndTable);
}
}
catch(Exception e){
e.printStackTrace();
}
As the column names in each table will be different, how to get the corresponding column names in "sql_stmt_1.executeQuery", so that once I get each record from the table, I have to insert it.
Like wise all the 110 tables data has to be inserted into XML file.
Please help me.
Thanks
Ramm
Try using following query for your column names in each table
select column_name from information_schema.columns
where table_name = 'YourTableName' //this will your iterated loop table name.
Using this query you will get all column names from your table add those column name in next query of that table.
then update the XML.