Parse a JDBC ResultSet into a CSV in-memory String - java

I am executing a query which is returning a ResultSet object. I want to convert this ResultSet into a CSV String in memory.
The reason I want to do this is that once I have the CSV String, I want to invoke a REST API endpoint and pass it this CSV data.
Are there any existing libraries or utilities I can use to convert from a ResultSet into an in memory String? I.e. not into a file..

StringWriter output = new StringWriter();
CsvWriterSettings settings = new CsvWriterSettings(); // many options here, check the documentation
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
String[] headers = new String[columns];
for(int i = 1; i <= columns; i++){
headers[i - 1] = md.getColumnLabel(i);
}
//if an input value is null, you may want print "NULL"
settings.setNullValue("NULL");
// if an input value is not null, but is empty (e.g. ""), the writer can be configured to print "NULL" as well
settings.setEmptyValue("NULL");
// Sets the file headers (used for finer selection of fields, these values won't be written automatically)
settings.setHeaders(headers);
// Creates a writer with the above settings;
CsvWriter writer = new CsvWriter(output, settings);
// Writes the headers specified in the settings
writer.writeHeaders();
Object[] row = new Object[columns];
while(rs.next()){
for(int i = 1; i <= columns; i++){
row[i - 1] = rs.getObject(i);
}
writer.writeRow(row);
}
writer.close();
String yourString = output.toString();

Related

how to get header properly while fetching to excel file

I have a file stored in blob in the database and I'm able to download the file on click to excel. Problem is that the header is coming in one line in spread on different columns because of after each column
"\"\t\"" "\t"
how to fix these
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(out, "ISO8859_1");
ecsvp_en = new ExcelCSVPrinter(osw);
String[] headers = list.get(0);
//Column Headers
ecsvp_en.println(headers);
// Data
int rowCount;
for (rowCount = 1; rowCount < list.size(); rowCount++) {
row = list.get(rowCount);
ecsvp_en.println(row);
}
Actual header :
"Contract Record Type\"\t\"Contract Type\"\t\"Contract Number\"\t\"Original Contract: Contract Number\"\t\"Contract Line Item Number\"\t\"Product: Product Name\"\t\"Name\"\t\"BMT #\"\t\"Service Status\"\t\"Created Date\"\t\"Effective Date"
Expected header :
"Contract Record Type\tContract Type\tContract Number\tOriginal Contract: Contract Number\tContract Line Item Number\tProduct: Product Name\tName\tBMT #\tService Status\tCreated Date\tEffective Date"

Fetching Data From xlsx sheet, not showing last three rows in jtable

I am trying to fetching data from excel sheet(.xlsx) file. when I use to print fetched data using
System.out.println(sheet.getRow(i).getCell(c).getStringCellValue()); I see the all the rows from excel sheet is fetched. But when I add this data in jtable it misses last three rows and shows following error:
Cannot invoke "org.apache.poi.xssf.usermodel.XSSFRow.getCell(int)" because the return value of "org.apache.poi.xssf.usermodel.XSSFSheet.getRow(int)" is null
enter code here
JFileChooser fileChooser = new JFileChooser("D:");
int returnValue = fileChooser.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
selectedFile = fileChooser.getSelectedFile();
FileName = selectedFile.getName();
String FilePath = selectedFile.getPath();
System.out.println(FileName);
System.out.println(FilePath);
File excelfile = new File(FileName);
try{
FileInputStream fis = new FileInputStream(selectedFile);
XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet sheet = wb.getSheetAt(0);
int totalrows = sheet.getPhysicalNumberOfRows();
for (int i = 0; i <=totalrows; )
{
dmodel.addRow(new Object[]{"" });
System.out.println(sheet.getRow(i).getCell(0).getStringCellValue()); // this line work
String name = sheet.getRow(i).getCell(0).getStringCellValue();
jTable1.setValueAt(name , i, 0); // this line does not work
i++ ;
}
JOptionPane.showMessageDialog(null, "All rows are fetched Successfully" );
}catch(Exception fx)
{
System.out.println(fx.getMessage());
// System.out.println(fx.getCause());
}
System.out.println(sheet.getRow(r).getCell(c).getStringCellValue()); // this line work
String name = sheet.getRow(i).getCell(c).getStringCellValue();
jTable1.setValueAt(name , i, 0); // this line does not work
Don't know if this will solve your problem, but the above code is not how you use System.out.println(...) to debug your logic.
To verify the data you use:
//System.out.println(sheet.getRow(r).getCell(c).getStringCellValue()); // this line work
String name = sheet.getRow(i).getCell(c).getStringCellValue();
System.out.println( name );
jTable1.setValueAt(name , i, 0); // this line does not work
Don't attempt to read the data twice. By assigning the data to a variable you are debugging the data in the variable. Don't repeat the nested methods multiple times.
Maybe the class expects you to only read the data once, so the second read gives the null value. The simple change above will prevent this.

Read Excel dynamically and store it in map

My requirement is to read the excel dynamically and store the contents in Map. The headers should be key and the respective column should be value so that when I pass the key, I can get the cell value.
My Excel sheet contains multiple rows and columns which can be changed dynamically. My intention is to write a common function in java to read an excel and store the contents in map. The Key should be column headers and the value should be respective cell value of the header. So while retrieving when I pass the header key, I should receive the respective cell value. My plan is to pass the row number and the key in a method so that it can retrieve the respective cell value related to the row as well as the key
static Map<String> excelMap = new LinkedHashMap<String>();
public static String readWriteExcel(String sheetName) throws EncryptedDocumentException, InvalidFormatException, IOException, JSONException
{
File file = new File("File Path");
FileInputStream inputStream = new FileInputStream( file );
Workbook workbook = WorkbookFactory.create( inputStream );
Sheet sheet = workbook.getSheet( sheetName );
int rowNumber =0;
int rowCount = sheet.getLastRowNum();
for(int i=1;i<=rowCount;i++){
Row row = sheet.getRow(0);
for(int j=0;j<row.getLastCellNum();j++) {
String key=row.getCell(j).getStringCellValue();
String value=sheet.getRow(rowNumber+1).getCell(j).getStringCellValue();
excelMap.put(key, value);
}
}
}
By looking at the code, i am assuming the issues: Multiple rows present in the sheet, but you are getting data of first row only.
Solution :
First of all, you need to store all rows data in a List of Map. where list index corresponds to the row number. Also You are not incrementing the rowNumber variable anywhere. Its always 0.
Why not directly use the variable i to get a particular row from sheet?
I think this should work.
static List<Map<String, String>> excelData = new ArrayList<HashMap<String, String>>();
public static String readWriteExcel(String sheetName) throws EncryptedDocumentException, InvalidFormatException, IOException, JSONException
{
File file = new File("File Path");
FileInputStream inputStream = new FileInputStream( file );
Workbook workbook = WorkbookFactory.create( inputStream );
Sheet sheet = workbook.getSheet( "sheetName" );
int rowCount = sheet.getLastRowNum();
for(int i=1;i<=rowCount;i++){
Row row = sheet.getRow(0);
Map<String,String> rowData = new HashMap<>();
for(int j=0;j<row.getLastCellNum();j++) {
String key=row.getCell(j).getStringCellValue();
String value=sheet.getRow(i).getCell(j).getStringCellValue();
rowData.put(key, value);
}
excelData.add(rowData);
}
}
Since you want to map multiple rows you have to store multiple rows.
One way is storing a map consisting column->list containing values for each row.
Another way is storing a map consisting column+row number->value.
Sample code for second method:
static Map<String, String> excelMap = new LinkedHashMap<String, String>();
...
// storing values
excelMap.put(key + "_" + i, value); // i is row index
...
// getting values
public static String getCellValue(String cellName, int rowIndex) {
return excelMap.get(cellName + "_" + rowIndex);
}

Adding headers to an excel file using Java

I have a problem with adding headers to the newly created .xlsx file
I would like to see the first header = 'UserName' and the second header = 'Password'. Can anyone help me on how to do this?
XSSFWorkbook new_workbook = new XSSFWorkbook(); // create a blank workbook object
XSSFSheet sheet = new_workbook.createSheet("EMP_DETAILS"); // create a worksheet with caption score_details
// Define the SQL query
String sql = "SELECT login, password FROM \"Permissions\"";
ResultSet rs = stmt.executeQuery(sql);
// Create Map for Excel Data
Map<String, Object[]> excel_data = new HashMap<String, Object[]>();
int row_counter = 0;
//Extract data from result set
while(rs.next()){
row_counter = row_counter+1;
String login = rs.getString("login");
String password = rs.getString("password");
excel_data.put(Integer.toString(row_counter), new Object[] {login, password});
}
rs.close();
// Load data into logical worksheet
Set<String> keyset = excel_data.keySet();
int rownum = 0;
for(String key : keyset){ // loop through the data and add them to the cell
Row row = sheet.createRow(rownum++);
Object [] objArr = excel_data.get(key);
int cellnum = 0;
for(Object obj : objArr){
Cell cell = row.createCell(cellnum++);
if(obj instanceof Double)
cell.setCellValue((Double)obj);
else
cell.setCellValue((String)obj);
}
}
FileOutputStream output_file = new FileOutputStream(new File("File.xlsx")); // create XLSX file
new_workbook.write(output_file); // write excel document to output stream
output_file.close(); // close the file
My $0.02... don't create an Excel file for something this simple. Instead create a CSV file. The first line you write will be
UserName, Password
for the headers and the lines after that will just be your data for each column separated by a comma. Once the file is written, you can easily open it in Excel and save it as an Excel file.
This method is way simpler and easier than trying to actually write an Excel file.
If you don't want to do that, you just need to create a row before you start looping through your keyset as you would any other row and write the strings for headers.
You can use following code after this line ResultSet rs = stmt.executeQuery(sql);:
ResultSetMetaData rsmd=rs.getMetaData();
Then to fetch column headers; use below:
String columnName1 = rsmd.getColumnName(1); // will fetch you "UserName"
String columnName2 = rsmd.getColumnName(2); // will fetch you "Password"

Performance : Writing oracle ResultSet into XLSX using Java, Apache-POI

I need to write 600-700k records into xlsx file using Apache POI.
the code I am presently using is :
public void writeRecords(ResultSet rs) {
try{
SXSSFWorkbook wb = new SXSSFWorkbook();
wb.setCompressTempFiles(true);
SXSSFSheet sh = (SXSSFSheet)wb.createSheet("Sheet 1");
Row row = null;
int numColumns = rs.getMetaData().getColumnCount();
// Workbook wb = ExcelFileUtil.createExcelWorkBook(true, 5);
sh.setRandomAccessWindowSize(100);// keep 100 rows in memory, exceeding rows will be flushed to disk
Row heading = sh.createRow(1);
ResultSetMetaData rsmd = rs.getMetaData();
for(int x = 0; x < numColumns; x++) {
Cell cell = heading.createCell(x+1);
cell.setCellValue(rsmd.getColumnLabel(x+1));
}
int rowNumber = 2;
int sheetNumber = 0;
while(rs.next()) {
row = sh.createRow(rowNumber);
for(int y = 0; y < numColumns; y++) {
row.createCell(y+1).setCellValue(rs.getString(y+1));
// wb.write(bos);
}
rowNumber++;
}
FileOutputStream out = new FileOutputStream("C:/Users/test1.xlsx");
wb.write(out);
out.close();
}
catch (Exception e){
e.printStackTrace();
}
It is working fine but it is taking ~50 minutes to write ~65k records.
Resultset of 65k records was fetched in 5-6 minutes.
Is there any way we can write 600,000-700,000 records in about 10-15 minutes
using POI.
We wont be able to export data into CSV format, as the endusers have setups to import xlsx files only.
regards,
Tushar
Check the fetchSize of the PreparedStatement. If it isn't explicitly set, the value may be very small compared with the reality of the table, and the speed of queries on medium-large amounts of data sees very affected.
Check this question for more information.
Also, consider if it's necessary to use setCompressTempFiles, or SXSSFWorkbook at all. If is needed, the value of rows keeps in memory will impact performance, in a directly proportional way.
it would be very fast if your able write file output form sqlplus .
create file as below mycsv.sql:
SET DEFINE OFF
SET ECHO OFF
SET SERVEROUTPUT OFF
SET TERMOUT OFF
SET VERIFY OFF
SET FEEDBACK OFF
SET PAGESIZE 10000
SET ARRAYSIZE 5000
REM SET HEAD OFF
SET LINE 500
spool /tmp/mycsvfile.csv;
select * from MY_table;
spool off;
exit;
and from Linux prompt you can run like
$> sqlplus username/password #/tmp/mycsv.sql

Categories

Resources