Delete specific rows from an Access table using Jackcess - java

I am using the Jackcess API with an Access database. I open the database and get a specific table. How can I get the data (rows) from this table which matches a list of ids?
For example get all the rows from the table where id is in List.
private List<Component> disabledComponentsIds;
private Database db = null;
db = Database.open(new File(target), false, false);
Table table = db.getTable("t_object");
Table packages = db.getTable("t_package");
for(Map<String, Object> r : table){
if(disabledComponentsIds.contains(r.get("ea_guid"))){
r.get("package_id");
//Delete row from t_package table where id = r.get("package_id")
}
}
In this particular case I want to delete the rows.

Given a table named "t_object" ...
object_id object_name
--------- -----------
1 alpha
2 bravo
3 charlie
4 delta
5 echo
... where "object_id" is the primary key, you could delete specific rows like so:
// test data
ArrayList<Integer> enabledComponentsIds = new ArrayList<>();
enabledComponentsIds.add(2);
enabledComponentsIds.add(3);
String dbFileSpec = "C:/Users/Public/jackcessTest.mdb";
try (Database db = DatabaseBuilder.open(new File(dbFileSpec))) {
Table t = db.getTable("t_object");
for (int id : enabledComponentsIds) {
Row r = CursorBuilder.findRowByPrimaryKey(t, id);
if (r != null) {
t.deleteRow(r);
}
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
That will delete the rows where "object_id" is 2 or 3.
Edit:
If the column is not indexed then you'll have to iterate through each row (as Kayaman suggested) and see if its column value is contained in the list:
// test data
ArrayList<Integer> enabledComponentsIds = new ArrayList<>();
enabledComponentsIds.add(2);
enabledComponentsIds.add(3);
String dbFileSpec = "C:/Users/Public/jackcessTest.mdb";
try (Database db = DatabaseBuilder.open(new File(dbFileSpec))) {
Table t = db.getTable("t_object");
for (Row r : t) {
if (enabledComponentsIds.contains(r.getInt("object_id"))) {
t.deleteRow(r);
}
}
} catch (Exception e) {
e.printStackTrace(System.err);
}

Jackcess provides very limited functionality for querying the data, so your best option is to go through the table with an iterator (or streams).
for(Row r : myTable)
; // perform any filtering based on rows here

Related

Java JTable data from database

I'm new to java and I need help with displaying a joined table/query in jtable.
First, I have done displaying data from 1 table which is:
Select data from 1 table
insert the result to its entity and insert each one of it to a List
return the list to view and insert row to jtable
I am using a DAO pattern, which has a factory, interface, implement, entity and view.
So what if I select data from other table?
Here is my get method in implement for getting book
public List get(String find) {
try {
ps = db.connect().prepareStatement("SELECT * FROM books WHERE title like ? ");
ps.setString(1, "%" + find + "%");
status = db.execute(ps);
if (status) {
books = db.get_result();
listBooks = new ArrayList<>();
while (books.next()) {
entity_books b = new entity_books();
b.setId(books.getInt(1));
b.setId_category(books.getInt(2));
b.setTitle(books.getString(3));
listBooks.add(b);
}
books.close();
return listBooks;
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return null;
}
and then in my view:
listBooks = booksDAO.get(find.getText());
model = (DefaultTableModel) book_table.getModel();
model.setRowCount(0);
listBooks.forEach((data) -> {
model.addRow(new Object[]{
data.getId(),
data.getId_category(),
data.getTitle(),
});
});
This works fine, but I want the query to join table so I can see the category name instead of just ID category. I can do the query, but how do I apply that to my code?
Here is the query for joined table
select title,category from book b
join category c on c.id = b.id_category
Normally if I select only 1 table, I would insert it to its entity ( book table -> book entity ), so how do I handle this with multiple tables?
I didn't use prepared statement, but this code works on my end.
String sql = "SELECT * FROM customer c JOIN company cmp ON c.company_idcompany = cmp.idcompany";
ResultSet rs = stmt.executeQuery(sql);
//STEP 5: Extract data from result set
while (rs.next()) {
//Retrieve this from customer table
int id = rs.getInt("idcustomer");
//Retrieve this from customer table
String username = rs.getString("company_username");
//Display values
System.out.println("ID: " + id);
System.out.println("Username: " + username);
}

Importing a CSV file through java and output is: java.sql.BatchUpdateException: Cannot add or update a child row: a foreign key constraint fails

I'm trying to import a CSV file like this through java into mysql db:
CODE |SIZE
994445|15
994471|15
994472|11
994473|11
994474|18
994475|15
994476|15
In the DB, it should insert into STORAGE table with attributes: OUTLET_code and size. CODE is an Outlet Code and SIZE refers to the storage size in that outlet; there can be more than one storage but not with the same size. Thus, both attributes are the primary keys, having a composite primary key for the STORAGE table. There are 2,000+ rows in the CSV file and only 439 rows are successfully being imported to mysql database. Here are my tables:
The first 439 rows enter but not the rest
OUTLET_code is a foreign key from OUTLET table. But both attributes are the primary keys for STORAGE table.
I dont get why the first 439 rows enter but not the rest. I'm using netbeans and this is my code for importing the file:
public static String importFile(){
String insertQuery = "INSERT INTO CABINET VALUES (?,?)";
String status;
try (CSVReader reader = new CSVReader(new FileReader("D:\\fullpathfilehere\\Cabinet.csv"), ','); Connection connection = DBConnection.getConnection();){
PreparedStatement pstmt = connection.prepareStatement(insertQuery);
String[] rowData = null;
int i = 0;
while((rowData = reader.readNext()) != null){
status = "Working";
for (String data : rowData){
pstmt.setString((i % 2) + 1, data);
if (++i % 2 == 0)
pstmt.addBatch();// add batch
if (i % 20 == 0)// insert when the batch size is 10
pstmt.executeBatch();
}
}
status = "Completed";
}catch (Exception e){
e.printStackTrace();
status = "Error - " + e.getMessage();
}
return status;
}
I've been using code above for other files to import into the database like employees and they have been successful. But for this, the output I receive is:
java.sql.BatchUpdateException: Cannot add or update a child row: a foreign key constraint fails (sandapp.cabinet, CONSTRAINT fk_CABINET_OUTLET1 FOREIGN KEY (OUTLET_code) REFERENCES outlet (code) ON DELETE NO ACTION ON UPDATE NO ACTION)
at com.mysql.jdbc.ServerPreparedStatement.executeBatch(ServerPreparedStatement.java:652)
at logic.ImportCabinet.importFile(ImportCabinet.java:28)
If anyone can help the would be really appreciated :)

Java RowFilter on multiple columns

I want to sort/filter a JTable on multiple columns, f.E.
Column1 Column2
a 1
b 2
c 2
I want to sort this table by the Column1 = b and by the Column2 = 2.
MyTableModel model = new MyTableModel();
sorter = new TableRowSorter<MyTableModel>(model);
table = new JTable(model);
table.setRowSorter(sorter);
...
private void newFilter() {
RowFilter<MyTableModel, Object> rf = null;
//If current expression doesn't parse, don't update.
try {
rf = RowFilter.regexFilter(filterText.getText(), 0);
} catch (java.util.regex.PatternSyntaxException e) {
return;
}
sorter.setRowFilter(rf);
}
But how to sort on more than one column?
you can create RowFilter.AndFilter and pass all filters that you need:
List<RowFilter<M, O>> listOfFilters = new ArrayList<>();
... add filters into list
RowFilter.andFilter(listOfFilters);
Simply remove the parameter "0" from the RowFilter to sort all columns:
rf = RowFilter.regexFilter(filterText.getText());

Get RowId from QueryChangeDescription

To my Oracle Database I have registered a DatabaseChangeNotification with a SQL-Query. I like to get any changes on the defined TABLE.
DatabaseChangeRegistration changeRegistration;
Properties properties = new Properties();
properties.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS, "true");
properties.setProperty(OracleConnection.DCN_QUERY_CHANGE_NOTIFICATION, "true")
changeRegistration = connection.registerDatabaseChangeNotification(properties);
DCNListener dcnListener = new DCNListener(this);
changeRegistration.addListener(this);
Statement statement = connection.createStatement();
((OracleStatement) statement).setDatabaseChangeRegistration(changeRegistration);
String sql = "SELECT * from TABLE";
statement.executeQuery(sql);
In my Listener I receive the DatabaseChangeEvents
public void onDatabaseChangeNotification(DatabaseChangeEvent databaseChangeEvent) {
TableChangeDescription[] tableChangeDescription = databaseChangeEvent.getTableChangeDescription();
QueryChangeDescription[] queryChangeDescription = databaseChangeEvent.getQueryChangeDescription();
for (QueryChangeDescription qcd: queryChangeDescription) {
String result = qcd.toString();
System.out.println(qcd);
}
}
tabelChangeDescription is null
My result is:
query ID=201, query change event type=QUERYCHANGE
Table Change Description (length=1): operation=[UPDATE], tableName=USER.TABLE, objectNumber=67385
Row Change Description (length=1):
ROW: operation=UPDATE, ROWID=AAAQc5AAHAAAAG/AAB
Is there any nice way to get the ROWID from the Changes row else than String-Parsing? I can't find any getRowId-Method on the QueryChangeDescription.
I found the was to get the RowId. From the queryChangeDescription you can get the TabeleChangeDesciptions which has nothing in Common with the TableChangeDecription from the event. If there are changes on more than one Table, these tables where listed in the Array.
Because I am registered to only one Table I don't have to iterate over the list.
After habing the the TableChangeDescriptionyou can get the RowChangeDescription for each changed row. From this you can get the RowId.
for (QueryChangeDescription queryChangeDescription : databaseChangeEvent.getQueryChangeDescription()) {
RowChangeDescription[] rowChangeDescriptions = queryChangeDescription.getTableChangeDescription()[0].getRowChangeDescription();
for (RowChangeDescription rowChangeDescription : rowChangeDescriptions) {
handleEvent(rowChangeDescription.getRowid());
}
}

how to generate sql query dynamically having specific colums

I have several tables. I have a query also. My problem is to generate the SQL query dynamically using Java.
I have the following fields in a separate table:
Collumn name status
po_number, Y
unit_cost, Y
placed_date , Y
date_closed, Y
scheduled_arrival_date Y
date_closed Y
order_quantity Y
roll_number N
product_sku N
product_category_name N
rec_vendor_quantity Y
vendor_name Y
et_conversion_unit_quantity Y
from which i have to generate a query when the status is Y, the problem here is some time the above columns
The following query is the out put of the above :
here i have inculded all the columns but i have to exculde the column which has the status of N, please help me to construt the query using java.
select
pi.po_number,poi.unit_cost,pi.placed_date CreateDate,
case when isnull(pi.date_closed) then pi.scheduled_arrival_date
else pi.date_closed end as ReceviedDate,
poi.order_quantity,poi.roll_number,p.product_sku product_name,
pc.product_category_name,poi.rec_vendor_quantity,pv.vendor_name,p.et_conversion_unit_quantity,pi.note
from
purchase_order as pi,
purchase_order_inventory as poi,
product_vendors as pv,
products AS p,
product_categories AS pc
where
pi.purchase_order_id=poi.purchase_order_id and
pc.product_category_id=p.product_category_id and
poi.product_id = p.product_id and
poi.product_category_id=pc.product_category_id and
pi.vendor_id=pv.product_vendor_id and
( ( pi.date_closed >= '2012-01-01' and pi.date_closed <='2012-09-05 23:59:59' )
or ( pi.scheduled_arrival_date >= '2012-01-01' and pi.scheduled_arrival_date <='2012-09-05 23:59:59') ) and
pi.po_type=0
and pi.status_id = 0 and poi.transaction_type = 0
order by pi.po_number
UPDATE :
QUERY : STEP 1:
SELECT rcm.id,rcm.tablename,rcm.columnname,rcm.size,rcm.displayorder,rcm.isactive FROM report_customise_master rcm where rcm.tablename !='employee' and rcm.isactive='Y' order by rcm.displayorder;
STEP 2 :
Java method to construct the query :
public Map getComplexReportQuery() {
String query = "SELECT rcm.id,rcm.tablename,rcm.columnname,rcm.size,rcm.displayorder,rcm.isactive FROM report_customise_master rcm where rcm.tablename !='employee' and rcm.isactive='Y' order by rcm.displayorder;";
String tableName = "", from = "", select = "";
StringBuffer sb = new StringBuffer();
Map<String, List<String>> resultsMap = new LinkedHashMap<String, List<String>>();
Map<String, String> displayOrderMap = new LinkedHashMap<String, String>();
Map queryMap = new LinkedHashMap();
if (!query.isEmpty() || query.length() > 0) {
sb.append(query);
}
Connection connection = getConnection();
if (connection != null) {
try {
PreparedStatement reportQueryPS = connection.prepareStatement(sb.toString());
ResultSet reportQuery_rst = reportQueryPS.executeQuery();
List<String> tables = new ArrayList<String>();;
if (reportQuery_rst != null) {
StringBuilder selectQuery = new StringBuilder(" SELECT ");
StringBuilder fromQuery = new StringBuilder(" FROM ");
while (reportQuery_rst.next()) {
tableName = reportQuery_rst.getString("tablename");
List<String> columns = resultsMap.get(tableName);
if (columns == null) {
columns = new ArrayList<String>();
resultsMap.put(tableName, columns);
}
columns = resultsMap.get(tableName);
String columnName = reportQuery_rst.getString("columnname");
columns.add(columnName);
}
tableName = "";
for (Entry<String, List<String>> resultEntry : resultsMap.entrySet()) {
tableName = resultEntry.getKey();
List<String> columns = resultEntry.getValue();
int i = 0;
for (String column : columns) {
selectQuery.append(tableName + "." + column);
if (i != columns.size()) {
selectQuery.append(",");
} else {
selectQuery.append("");
}
i++;
}
if (!tables.contains(tableName)) {
tables.add(tableName);
}
}
//to remove comma at the end of line
select = selectQuery.toString().replaceAll(",$", "");
tableName = "";
int i = 0;
for (String table : tables) {
fromQuery.append(table);
fromQuery.append(" ");
fromQuery.append(table);
if (i != tables.size()) {
fromQuery.append(",");
} else {
fromQuery.append("");
}
i++;
}
from = fromQuery.toString().replaceAll(",$", "");
queryMap.put("query", select + from);
}
//from = from+"ORDER BY "+orderbyColumn+" "+sort+" ";
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
closeConnection(connection, null, null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
} else {
System.out.println("Connection not Established. Please Contact Vendor");
}
return queryMap;// return the map/ list which contains query and sory and display order
}
STEP 3 : Result query
{query= SELECT purchase_order.po_number,purchase_order.placed_date,purchase_order.date_closed,purchase_order.scheduled_arrival_date,purchase_order_inventory.unit_cost,purchase_order_inventory.order_quantity,purchase_order_inventory.roll_number,purchase_order_inventory.rec_vendor_quantity,products.product_sku,products.et_conversion_unit_quantity,product_categories.product_category_name ,product_vendors.vendor_name FROM purchase_order purchase_order,purchase_order_inventory purchase_order_inventory,products products,product_categories product_categories,product_vendors product_vendors}
but this not what i wanted, Please help me to construct the query i have given.
Two queries
You need to make two queries:
Query which fields are enabled
Build the second query string (the one you want to build dinamically)
It's this way because a SQL query has to tell which columns will be included before querying any data. In fact it will be used to build the internal DB query plan, it is, the way the DB motor will use to retrieve and organize the data you ask.
Query all columns
Is it necesary to query only that fields? Can't you query everything and use the relevant data?
Joins
Looking at the updated question I guess you need to dynamically add where conditions to join tables correctly. What I should do is have a reference telling me what coindition to add when a table is present.
There are at least two options:
Based on table pairs present (by example: "if A and B are present then add A.col1 = B.col2")
Based on tables present ("if B is present, then add A.col1 = B.col2; A should be present"
Based on your example I think the second option is more suitable (and easy to implement).
So I should have some static Map<String, JoinInfo> where JoinInfo has at least:
JoinInfo
+ conditionToAdd // by example "A.col1 = B.col2"
+ dependsOnTable // by example "A" to indicate that A must be present when B is present
So you can use:
that info to add tables that should be (by example: even if A has no selected cols, must be present to join with B)
include the conditionToAdd to the where clause
Anyway... I think you are getting into much trouble. Why so dynamic?
You have to approach the thing step by step.
Firstly you have to create a query that will return all rows that have status='Y'
Then you will put the COLUMN_NAME in a list of Strings.
List<String> list = new List<String>();
while(rs.next()){
list.add(rs.getString(columnNumber));
}
And then you have to loop the List and generate dynamically your second sql statement
String sqlSelect = "SELECT ";
String sqlFrom = " FROM SOME_OTHER_TABLE "
String sqlWhere = " WHERE SOME_CONDITION = 'SOME_VALUE' "
for(String x : list){
sqlFrom += x +" , "+;
}
//here make sure that you remove the last comma from sqlFrom because you will get an SQLException
String finalSql = sqlSelect + sqlFrom + sqlWhere ;

Categories

Resources