Im trying to parse a pipe delimited file and insert fields into a table. when i start the application nothing happens in my DB. My DB has 4 columns (account_name, command_name, and system_name, CreateDt). The file i am parsing has the date in the first row then extra data. The rows following i only need the first 3 fields in each the rest is extra data. the last row is the row count. i skipped the inserting date because for now but want to get back to it after at least able to insert the first 3 fields. I have little experience with parsing a file and storing data in a DB and have looked through jdbc examples to get to this point but im struggling and am sure there is a better way.
File Example
20200310|extra|extra|extra||
Mn1223|01192|windows|extra|extra|extra||
Sd1223|02390|linux|extra|extra|extra||
2
table format
account_name command_name system_name createDt
Mn1223 01192 windows 20200310
Sd1223 02390 linux 20200310
Code to parse and insert into DB
public List insertZygateData (List<ZygateEntity> parseData) throws Exception {
String filePath = "C:\\DEV\\Test_file.xlsx";
List<String> lines = Files.readAllLines(Paths.get(filePath));
// remove date and amount
lines.remove(0);
lines.remove(lines.size() - 1);
for (ZygateEntity zygateInfo : parseData){
new MapSqlParameterSource("account_name", zygateInfo.getAccountName())
.addValue("command_name", zygateInfo.getCommandName())
.addValue("system_name", zygateInfo.getSystemName())
.getValues();
}
return lines.stream()
.map(s -> s.split("[|]")).map(val -> new ZygateEntity(val[0],val[1],val[2])).collect(Collectors.toList());
}
public boolean cleantheTable() throws SQLException {
String sql = "INSERT INTO Landing.midrange_xygate_load (account_name,command_name,system_name)"+
"VALUES (:account_name,:command_name,:system_name)";
boolean truncated = false;
Statement stmt = null;
try {
String sqlTruncate = "truncate table Landing.midrange_xygate_load";
jdbcTemplate.execute(sqlTruncate);
truncated = true;
} catch (Exception e) {
e.printStackTrace();
truncated = false;
return truncated;
} finally {
if (stmt != null) {
jdbcTemplate.execute(sql);
stmt.close();
}
}
log.info("Clean the table return value :" + truncated);
return truncated;
}
}
Entity/Model
public ZygateEntity(String accountName, String commandName, String systemName){
this.accountName=accountName;
this.commandName=commandName;
this.systemName=systemName;
}
//getters and setters
#Override
public String toString() {
return "ZygateEntity [accountName=" + accountName + ", commandName=" + commandName + ", systemName=" + systemName + ", createDt=" + createDt +"]";
}
}
Taking a look at what you've provided, it seems you have a jumbled collection of bits of code, and while most of it is there, it's not all there and not quite all in the right order.
To get some kind of clarity, try to break down what it is you're doing into separate steps, and have a method that focuses on each step. In particular, you write
Im trying to parse a pipe delimited file and insert fields into a table
This naturally breaks down into two parts:
parsing the pipe-delimited file, and
inserting fields into a table.
For the first part, you seem to have most of the parts already in your insertZygateData method. In particular, this line reads all the lines of a file into a list:
List<String> lines = Files.readAllLines(Paths.get(filePath));
These lines then remove the first and last lines from the list of lines read:
// remove date and amount
lines.remove(0);
lines.remove(lines.size() - 1);
You then have some code that looks a bit out of place: this seems to be something to do with inserting into the database, but we haven't created our list of ZygateEntity objects as we haven't yet finished reading the file. Let's put this for loop to one side for the moment.
Finally, we take the list of lines we read, split them using pipes, create ZygateEntity objects from the parts and create a List of these objects, which we then return.
return lines.stream()
.map(s -> s.split("[|]")).map(val -> new ZygateEntity(val[0],val[1],val[2])).collect(Collectors.toList());
Putting this lot together, we have a useful method that parses the file, completing the first part of the task:
private List<ZygateEntity> parseZygateData() throws IOException {
String filePath = "C:\\DEV\\Test_file.xlsx";
List<String> lines = Files.readAllLines(Paths.get(filePath));
// remove date and amount
lines.remove(0);
lines.remove(lines.size() - 1);
return lines.stream()
.map(s -> s.split("[|]")).map(val -> new ZygateEntity(val[0],val[1],val[2])).collect(Collectors.toList());
}
(Of course, we could add a parameter for the file path to read, but in the interest of getting something working, it's OK to stick with the current hard-coded file path.)
So, we've got our list of ZygateEntity objects. How do we write a method to insert them into the database?
We can find a couple of the ingredients we need in your code sample. First, we need the SQL statement to insert the data. This is in your cleanThetable method:
String sql = "INSERT INTO Landing.midrange_xygate_load (account_name,command_name,system_name)"+
"VALUES (:account_name,:command_name,:system_name)";
We then have this loop:
for (ZygateEntity zygateInfo : parseData){
new MapSqlParameterSource("account_name", zygateInfo.getAccountName())
.addValue("command_name", zygateInfo.getCommandName())
.addValue("system_name", zygateInfo.getSystemName())
.getValues();
}
This loop creates a MapSqlParameterSource out of each ZygateEntity object, and then converts it to a Map<String, Object> by calling the getValues() method. But then it does nothing with this value. Effectively you're creating these objects and getting rid of them again without doing anything with them. This isn't ideal.
A MapSqlParameterSource is used with a Spring NamedParameterJdbcTemplate. Your code mentions a jdbcTemplate, which appears to be a field within the class that parses data and inserts into the database, but you don't show the full code of this class. I'm going to have to assume it's a NamedParameterJdbcTemplate rather than a 'plain' JdbcTemplate.
A NamedParameterJdbcTemplate contains a method update that takes a SQL string and a SqlParameterSource. We have a SQL string, and we're creating MapSqlParameterSource objects, so we can use these to carry out the insert. There's not a lot of point in creating one of these MapSqlParameterSource objects only to convert it to a map, so let's remove the call to getValues().
So, we now have a method to insert the data into the database:
public void insertZygateData(List<ZygateEntity> parseData) {
String sql = "INSERT INTO Landing.midrange_xygate_load (account_name,command_name,system_name)"+
"VALUES (:account_name,:command_name,:system_name)";
for (ZygateEntity zygateInfo : parseData){
SqlParameterSource source = new MapSqlParameterSource("account_name", zygateInfo.getAccountName())
.addValue("command_name", zygateInfo.getCommandName())
.addValue("system_name", zygateInfo.getSystemName());
jdbcTemplate.update(sql, source);
}
}
Finally, let's take a look at your cleanThetable method. As with the others, let's keep it focused on one task: it looks like at the moment you're trying to delete the data out of the table and then insert it in the same method, but let's have it just focus on deleting the data as we've now got a method to insert the data.
We can't immediately get rid of the String sql = ... line, because the finally block in your code uses it. If stmt is not null, then you attempt to run the INSERT statement and then close stmt.
However, stmt is never assigned any value other than null, so it remains null. stmt != null is therefore always false, so the INSERT statement never runs. Your finally block never does anything, so you would be best off removing it altogether. With your finally block gone, you can also get rid of your local variable stmt and the sql string, leaving us with a method whose focus is to truncate the table:
public boolean cleantheTable() throws SQLException {
boolean truncated = false;
try {
String sqlTruncate = "truncate table Landing.midrange_xygate_load";
jdbcTemplate.execute(sqlTruncate);
truncated = true;
} catch (Exception e) {
e.printStackTrace();
truncated = false;
return truncated;
}
log.info("Clean the table return value :" + truncated);
return truncated;
}
I'll leave it up to you to write the code that calls these methods. I wrote some code for this purpose, and it ran successfully and inserted into a database.
So, in summary, no data was being written to your database because you were never making a call to the database to insert any. In your insertZygateData method you were creating the parameter-source objects but not doing anything useful with them, and in your cleanThetable method, it looked like you were trying to insert data, but your line jdbcTemplate.execute(sql) that attempted to do this never ran. Even if stmt wasn't null, this line wouldn't work as you didn't pass the parameter values in anywhere: you would get an exception from the database as it would be expecting values for the parameters but you never gave it any.
Hopefully my explanation gives you a way of getting your code working and helps you understand why it wasn't.
I have a VoltDB database with a table.
I want get the result of my VoltDB stored procedure. This is the code
import org.voltdb.*;
public class isola extends VoltProcedure {
public final SQLStmt getLeast = new SQLStmt(" SELECT codice FROM prova WHERE ID=1;" );
public VoltTable[] run() throws VoltAbortException {
voltQueueSQL(getLeast);
VoltTable[] queryresults = voltExecuteSQL();
String results= queryresults[0].toString();
System.out.println("String: \n " + results);
return voltExecuteSQL();
}
}
And this is the output
String:
header size: 14
status code: -128 column count: 1
(CODICE:INTEGER), rows -
2
The correct result of query is only 2.
Why do I get this result? I want to have only 2 as a result.
Thanks in advance
queryresults[0] is a VoltTable object. The toString() method is converting that entire object into a String (which does not include the data itself, only metadata). You need to iterate through the rows in the VoltTable (usually this is done using advanceRow()) and retrieve the codice column using either getLong(0) or getLong("CODICE").
Also, the final return voltExecuteSQL() is going to return an empty VoltTable[] because the queued SQL statement was already executed and nothing else has been queued.
I am writing Java Code to get data from SAP BAPI using Java Connector (JCo). This is my first time to make a connection to SAP using JCo. I was able to get the Tables available in the Data Source and also get one particular Table and Number of Columns using table_name.getNumColumns() which gives me the total count of columns. But when I do, table_name.getNumRows(), it says 0. Where as in my Data source, there are around 85 Rows. How can I get the rows from this table?
The code I have been using:
public class SapConnection {
public static void gettingTableData(JCoFunction function) {
JCoParameterList table_list = function.getTableParameterList();
JCoTable my_table = function.getTableParameterList().getTable("SOME_TABLE");
System.out.println("Field Count: "+my_table.getFieldCount());
// This is not working as Number of Rows is 0.
for(int i = 0; i<my_table.getNumRows(); i++, my_table.nextRow()) {
// get those rows and do something ..
}
System.out.println("Is Empty: "+my_table.isEmpty()); // returns True
System.out.println("Is First Row: "+my_table.isFirstRow()); // returns false
System.out.println("Next Row: "+my_table.nextRow()); // returns false
System.out.println("Num Rows: "+my_table.getNumRows()); // returning 0
}
public static void loadDataSourceAndGetData(JCoDestination dest) throws JCoException {
JCoRepository sapRepository = dest.getRepository();
JCoFunctionTemplate template =
sapRepository.getFunctionTemplate("DATA_SOURCE_NAME");
JCoFunction my_function = template.getFunction();
gettingTableData(my_function);
}
public static void main(String[] args) throws JCoException {
// get the Properties created for connection.
Properties pp = getJcoProperties();
PropertiesDestinationDataProvider pddp = new PropertiesDestinationDataProvider(pp);
Environment.registerDestinationDataProvider(pddp);
JCoDestination dest = getDestination();
try {
// Using JCo Context for stateful function calls to Start() and End()
JCoContext.begin(dest);
loadDataSourceAndGetData(dest);
JCoRepository sapRepository = dest.getRepository();
System.out.println(sapRepository.getMonitor().getLastAccessTimestamp());
} finally {
// end the connection.
JCoContext.end(dest);
}
}
}
If you would like to get some data from a SAP BAPI it would help a lot also to call this BAPI. The data doesn't materialize automatically in the JCo objects out of thin air.
In your code you do not execute any JCoFunction.
Set the mandatory import parameter values for this BAPI (if there are any), execute the BAPI (your JCoFunction object) and then you will get the export data from the SAP system in response which will then also add appropriate rows to the JCoTable object.
Trying to use a similar example from the sample code found here
My sample function is:
void query()
{
String nodeResult = "";
String rows = "";
String resultString;
String columnsString;
System.out.println("In query");
// START SNIPPET: execute
ExecutionEngine engine = new ExecutionEngine( graphDb );
ExecutionResult result;
try ( Transaction ignored = graphDb.beginTx() )
{
result = engine.execute( "start n=node(*) where n.Name =~ '.*79.*' return n, n.Name" );
// END SNIPPET: execute
// START SNIPPET: items
Iterator<Node> n_column = result.columnAs( "n" );
for ( Node node : IteratorUtil.asIterable( n_column ) )
{
// note: we're grabbing the name property from the node,
// not from the n.name in this case.
nodeResult = node + ": " + node.getProperty( "Name" );
System.out.println("In for loop");
System.out.println(nodeResult);
}
// END SNIPPET: items
// START SNIPPET: columns
List<String> columns = result.columns();
// END SNIPPET: columns
// the result is now empty, get a new one
result = engine.execute( "start n=node(*) where n.Name =~ '.*79.*' return n, n.Name" );
// START SNIPPET: rows
for ( Map<String, Object> row : result )
{
for ( Entry<String, Object> column : row.entrySet() )
{
rows += column.getKey() + ": " + column.getValue() + "; ";
System.out.println("nested");
}
rows += "\n";
}
// END SNIPPET: rows
resultString = engine.execute( "start n=node(*) where n.Name =~ '.*79.*' return n.Name" ).dumpToString();
columnsString = columns.toString();
System.out.println(rows);
System.out.println(resultString);
System.out.println(columnsString);
System.out.println("leaving");
}
}
When I run this in the web console I get many results (as there are multiple nodes that have an attribute of Name that contains the pattern 79. Yet running this code returns no results. The debug print statements 'in loop' and 'nested' never print either. Thus this must mean there are not results found in the Iterator, yet that doesn't make sense.
And yes, I already checked and made sure that the graphDb variable is the same as the path for the web console. I have other code earlier that uses the same variable to write to the database.
EDIT - More info
If I place the contents of query in the same function that creates my data, I get the correct results. If I run the query by itself it returns nothing. It's almost as the query works only in the instance where I add the data and not if I come back to the database cold in a separate instance.
EDIT2 -
Here is a snippet of code that shows the bigger context of how it is being called and sharing the same DBHandle
package ContextEngine;
import ContextEngine.NeoHandle;
import java.util.LinkedList;
/*
* Class to handle streaming data from any coded source
*/
public class Streamer {
private NeoHandle myHandle;
private String contextType;
Streamer()
{
}
public void openStream(String contextType)
{
myHandle = new NeoHandle();
myHandle.createDb();
}
public void streamInput(String dataLine)
{
Context context = new Context();
/*
* get database instance
* write to database
* check for errors
* report errors & success
*/
System.out.println(dataLine);
//apply rules to data (make ContextRules do this, send type and string of data)
ContextRules contextRules = new ContextRules();
context = contextRules.processContextRules("Calls", dataLine);
//write data (using linked list from contextRules)
NeoProcessor processor = new NeoProcessor(myHandle);
processor.processContextData(context);
}
public void runQuery()
{
NeoProcessor processor = new NeoProcessor(myHandle);
processor.query();
}
public void closeStream()
{
/*
* close database instance
*/
myHandle.shutDown();
}
}
Now, if I call streamInput AND query in in the same instance (parent calls) the query returns results. If I only call query and do not enter ANY data in that instance (yet web console shows data for same query) I get nothing. Why would I have to create the Nodes and enter them into the database at runtime just to return a valid query. Shouldn't I ALWAYS get the same results with such a query?
You mention that you are using the Neo4j Browser, which comes with Neo4j. However, the example you posted is for Neo4j Embedded, which is the in-process version of Neo4j. Are you sure you are talking to the same database when you try your query in the Browser?
In order to talk to Neo4j Server from Java, I'd recommend looking at the Neo4j JDBC driver, which has good support for connecting to the Neo4j server from Java.
http://www.neo4j.org/develop/tools/jdbc
You can set up a simple connection by adding the Neo4j JDBC jar to your classpath, available here: https://github.com/neo4j-contrib/neo4j-jdbc/releases Then just use Neo4j as any JDBC driver:
Connection conn = DriverManager.getConnection("jdbc:neo4j://localhost:7474/");
ResultSet rs = conn.executeQuery("start n=node({id}) return id(n) as id", map("id", id));
while(rs.next()) {
System.out.println(rs.getLong("id"));
}
Refer to the JDBC documentation for more advanced usage.
To answer your question on why the data is not durably stored, it may be one of many reasons. I would attempt to incrementally scale back the complexity of the code to try and locate the culprit. For instance, until you've found your problem, do these one at a time:
Instead of looping through the result, print it using System.out.println(result.dumpToString());
Instead of the regex query, try just MATCH (n) RETURN n, to return all data in the database
Make sure the data you are seeing in the browser is not "old" data inserted earlier on, but really is an insert from your latest run of the Java program. You can verify this by deleting the data via the browser before running the Java program using MATCH (n) OPTIONAL MATCH (n)-[r]->() DELETE n,r;
Make sure you are actually working against the same database directories. You can verify this by leaving the server running. If you can still start your java program, unless your Java program is using the Neo4j REST Bindings, you are not using the same directory. Two Neo4j databases cannot run against the same database directory simultaneously.
I have a field in my dataset defined as:
DataSourceDateTimeField dateField = new DataSourceDateTimeField("date");
and a StaticTextItem in DynamicForm defined as
StaticTextItem dateItem = new StaticTextItem("date", "Date");
I played a lot with different combinations of setDateFormatter, but datetime values are still rendered as something like 2011-08-23T20:00:00 (datasource receives it in json as a yyyy-MM-dd'T'HH:mm:ss.SSSZ field).
Is there some easy way to output datetime values to StaticTextItem? I assume using DynamicForm.fetchData().
UPD1. Data example.
Table row in PgSQL:
1 | "2011-09-29 12:10:05.010276+04" | "Europe"
Data sent by REST service:
{
"location":"Europe",
"id":1,
"date":"2011-09-29T08:10:05.010+0000"
}
Data fetched by SGWT from REST service (I dumped it with JSON.encode(XMLTools.selectObjects(data, "/").getJavaScriptObject()) in my implementation of transformResponse()) :
{
"location":"Europe",
"id":1,
"date":"2011-09-29T08:10:05"
}
Value as rendered in StaticTextField:
2011-09-29T08:10:05
So datetime values returned by server seem to conform the standard and also I have no warnings in Developer Console.
UPD2. May be I'm doing something wrong in my transformResponse() ?
protected void transformResponse(DSResponse response, DSRequest request, Object data) {
String json = JSON.encode(XMLTools.selectObjects(data, "/").getJavaScriptObject());
SC.logWarn("Response received");
SC.logWarn(json);
Record[] records = jsonToRecords(json);
//safe HTML text values
for (Record rec: records) {
for (DataSourceField field: getFields()) {
if (field.getType() == FieldType.TEXT) {
String textVal = rec.getAttribute(field.getName());
if (textVal != null) {
textVal = SafeHtmlUtils.htmlEscape(textVal);
}
rec.setAttribute(field.getName(), textVal);
}
}
}
response.setData(records);
response.setStartRow(0);
response.setEndRow(records.length);
response.setTotalRows(records.length);
}
/**
* Converts JS-array into SmartGWT records
*/
public static native ListGridRecord[] jsonToRecords(String jsonString) /*-{
var json = eval(jsonString);
return #com.smartgwt.client.widgets.grid.ListGrid::convertToListGridRecordArray(Lcom/google/gwt/core/client/JavaScriptObject;)(json);
}-*/;
Your problem is most likely that your date value is still a String, not an instance of Date. It should have been parsed into a Date when the JSON response was received - if it was not, there will be a warning in the SmartGWT Developer Console tell you so.
The format expected for date values in documented under DataSource.dataFormat - XML Schema date/datetime format is expected by default, and you can provide a FieldValueParser if you are unable to make your server produce this format.