How can I detect an access DB table with no columns? - ms-access

I have a support tool I have written that allows me to create a table in MS Access DB file. Because of the support, I set it so it just creates the table without any columns defined. There is another part of the same program which allows column creations. However when I select the table in my list, I try to load the table. Since the table is empty, the system throws an error at the Fill (I understand the Select is the cause). Is there a way to ask if a table has any columns before trying to load that table?
public static bool ConnectToDatabase(string dbTable)
{
return ConnectToDatabaseWStr(dbTable, "Select * From `" + dbTable + "`");
}
public static bool ConnectToDatabaseWStr(string dbTable, string strSQL)
{
try
{
conn = new OleDbConnection(connectionString);
}
catch (Exception e)
{
LogFile.write(1, "DataAccess: error detected when creating OLEDBConnection.\nConnection string:\n" + connectionString + "\n" + e.ToString() + "\n");
}
try
{
dataAdapter = new OleDbDataAdapter(strSQL, conn);
dataAdapter.Fill(DataSetList[iCurrDataSetListIndex].DataSetInstance, dbTable);

This is easy if there are columns.
You can even go SELECT * from tableName where ID = 0
And then for each the column names. However, while the above will return 0 rows, the columns still do come through. However, without ANY columns, then the above will fail, and you would in theory have to know the "ID" column existed.
You can thus get oleDB provider to return a table as a "schema". This is table of ROWS of the defined table. Thus you can use this:
If NO rows are returned, then we don't have a table that lays out and defines the schema:
var strTableName = "tblHotels";
OleDbConnection myCon = new OleDbConnection(My.Settings.TestDB);
myCon.Open();
string[] SchemaParams = new[] { null, null, strTableName, null };
DataTable MyTable = myCon.GetSchema("Columns", SchemaParams);
if (MyTable.Rows.Count == 0)
// no columns for table
Debug.Print("no columns in table");
else
foreach (DataRow MyRow in MyTable.Rows)
Debug.Print(MyRow("Column_Name") + "->" + MyRow("Data_Type"));

Related

Java FXML - NetBeans - Delete from Table - MySQL

I get the following error when I attempt to delete a row from TableView:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '[value: 3]' at line 1
What I want: Once a row from TableView is selected, I want to delete it from database.
#FXML
void delete(ActionEvent event) {
try {
int pos;
pos = (int) tabelCustomers.getSelectionModel().getSelectedIndex();
Customers c;
c = tabelCustomers.getItems().get(pos);
SimpleIntegerProperty idc = c.idc;
String query;
query = "DELETE FROM customers WHERE customers.idc = " + idc;
try (Statement stm = cnx.createStatement()) {
stm.executeUpdate(query);
}
} catch (SQLException ex) {
Logger.getLogger(CustomersTableController.class.getName()).log(Level.SEVERE,
null, ex);
}
}
What am I missing? I have tried a lot of possible solutions, nothing works.
Basically, when a user clicks on the row in a table and then clicks on the "remove" button, that row should be deleted from table and DB.
Thanks in advance.
SimpleIntegerProperty idc = c.idc;
String query = "DELETE FROM customers WHERE customers.idc = " + idc;
When an Object (that is not a String) is used in string concatenation it is automatically converted into a String by calling toString() on it. The string representation of SimpleIntegerProperty is not simply its value, which means your query ends up looking something like:
DELETE FROM customers WHERE customers.idc = IntegerProperty [bean: <some_instance>, name: idc, value: 42]
Which is obviously not valid SQL. You need to extract the value of the property and use that as part of the query. However, you should not use string concatenation when creating SQL queries in the first place. You should instead be using a PreparedStatement with parameters. For example:
String query = "DELETE FROM customers WHERE customers.idc = ?";
try (PreparedStatement ps = cnx.prepareStatement(query)) {
ps.setInt(1, idc.get());
ps.executeUpdate();
}

Can't delete form database SQLGrammarException

I want to DELETE column from base in hibernate where my inserted -regBroj- parameter is same as one in a base.
This is my method in controller for deleting.But i constantly get
SQLGrammarException:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'BG026CH' in 'where clause'
This 'BG026CH' is value of regBroj that i use as a parameter to find vehicle in database and delete it.And i insert it in text area in adminPage.
public String izbrisi(String regBroj) {
List<Vozilo> lista = listaj();
Session s = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction t = s.beginTransaction();
for (int i = 0; i < lista.size(); i++) {
if (regBroj .equals(lista.get(i).getRegBroj())) {
String izbrisiquery = "DELETE FROM Korisnik WHERE brojLk=" + regBroj + "";
Query q = s.createQuery(izbrisiquery);
int a = q.executeUpdate();
t.commit();
return "adminPage";
}
}
t.commit();
return "error";
}
Please replace below string with these one
String izbrisiquery = "DELETE FROM Korisnik WHERE brojLk='" + regBroj + "'";
You should consider using prepared statements because they will automatically take care of escaping field values with quotes, and they will also protect you from SQL injection.
// obtain a Connection object using your Hibernate session, or through some other means
Connection conn = getDBConnection();
for (int i = 0; i < lista.size(); i++) {
if (regBroj .equals(lista.get(i).getRegBroj())) {
String izbrisiquery = "DELETE FROM Korisnik WHERE brojLk = ?";
PreparedStatement ps = conn.prepareStatement(izbrisiquery);
ps.setString(1, regBroj);
ps.executeUpdate();
t.commit();
return "adminPage";
}
}
To see how SQL injection works, or how a malicious user could wreck the Korisnik table, imagine that someone hacks the UI to pass a value of '' OR TRUE for brojLK. This is what the resulting DELETE statement would look like:
DELETE FROM Korisnik WHERE brojLk = '' OR TRUE
In other words, this injected query would drop your entire table! Prepared statements would choke on this input and a hacker would not get as far as executing the query.

hibernate query for Getting json key value pair with joins

I am using REST , hibernate query language for getting some data from database with the help of joins in that query i need to fetch columns from two or more tables and i am getting the result record , and when i return that object through REST as json i am getting the json as in the follwoing format
{"table1col1value","table2col1value","table3colvalue","table1col2value","table2col2value"}
but i need to get the json data in the following format
{"table1colname1":"table1col1value","table2colname":"table2col1value","table1colname":"table3colvalue","table1colname":"table1col2value","table2colname":"table2col2value"}
for that i am using the following code and its working fine, but its working with sql query only i need it in HQL , please help me in this.
#Override
#Transactional
public List<Map<String,Object>> getMixProperties(List<String> keys,Set<String> s) {
StringBuilder sb = new StringBuilder();
sb.append("select ");
Iterator<String> i = keys.iterator();
int q = keys.size();
while (i.hasNext()) {
q=q-1;
if(q==0){
String n= i.next();
sb.append(" "+n);
}
else{
String n2= i.next();
sb.append(" "+n2+",");}
}
sb.append(" from Book Book "
+ " join Systems Systems ON Systems.idSystems =Book.idSystems "
+ " join Machine Machine ON Machine.id =Systems.id ");
/*Iterator<String> iterator = s.iterator();
int q2 = s.size();String s5 = null;
while(iterator.hasNext()) {
String s4 = iterator.next();
q2=q2-1;
if(q2==0){
sb.append(" "+s4+" "+s4);
}
else{
s5=s4;
sb.append(" "+s4+" "+s4+",");}
}*/
System.out.println("query "+sb);
String sbb = sb.toString();
Query query=sessionFactory.getCurrentSession().createSQLQuery(sbb);
query.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List<Map<String,Object>> aliasToValueMapList=query.list();
return aliasToValueMapList;
}
in this above code List keys will be the column name of different tables and (set s will be table names, but i am not using it in current code)
even this is working only if i have both class and db table name are same and property and column names are same, if its not same then its not working.
I am getting JSON only if i have the pojo class , but in my case result set can be any number of columns so its depends on runtime only , please help me in this

Cannot use data types with jackcess to export DB to csv

So I have a program that selects a DB and exports it as a csv. It appears when I export the DB the tab delimitation does not keep any data types. The csv ideally should keep text fields as "####","##"
instead of just ####,##.
Although the fields are "numbers" they have no need to be treated as numbers. This lack of formatting causes a small issue with sorting and I can see jackcess supports data types but will I need to use the cursor to keep these datatypes or can I still use the exportFile() function?
public DBTool() {
JOptionPane.showMessageDialog(null, "Select an access database file to be converted to .csv");
String userhome = System.getProperty("user.home");
JFileChooser chooser = new JFileChooser(userhome);
//chooser.setCurrentDirectory(new java.io.File("."));
chooser.setDialogTitle("Choose Database to Convert");
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
System.out.println("getCurrentDirectory(): " + chooser.getCurrentDirectory());
System.out.println("getSelectedFile() : " + chooser.getSelectedFile());
source = chooser.getSelectedFile().toString();
destination = chooser.getCurrentDirectory() + "\\output.csv";
System.out.println("Source: " + source);
System.out.println("Destination: " + destination);
} else {
System.out.println("No Selection ");
}
}
public void openEDB(){
sourceF = new File(source);
long length = sourceF.length();
System.out.println(length);
try {
try {
db = new DatabaseBuilder(sourceF)
.setCodecProvider(new CryptCodecProvider("password"))
.open();
} catch (IOException ex) {
Logger.getLogger(DBTool.class.getName()).log(Level.SEVERE, null, ex);
}
db = DatabaseBuilder.open(sourceF);
} catch (IOException ex) {
Logger.getLogger(DBTool.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void exportDB(){
destinationF = new File(destination);
try {
ExportUtil.exportFile(db, "TableName", destinationF);
JOptionPane.showMessageDialog(null, "Success, .csv created: " + this.destination);
} catch (IOException ex) {
Logger.getLogger(DBTool.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I'm not aware of a way to force Jackcess to enclose all text fields in double quotes when exporting. However, that would not affect the order in which the rows are exported by Jackcess anyway.
When using exportFile(), Jackcess will export the rows in natural order, which is the order in which the rows physically exist in the table (often, but not always, the order in which the rows were inserted into the table).
When using exportWriter() with a Cursor, Jackcess will export the rows in the order defined by the Cursor. So, if the field on which you want to sort the output has an index on it then you can create an IndexCursor and use exportWriter() with that Cursor to dump the rows to CSV.
If the field on which you want to sort the output does not have an index on it and you are unable (or unwilling) to create such an index in the Access database then another approach would be to use the UCanAccess JDBC driver to create a ResultSet based on an SQL statement that has an ORDER BY clause, then use something like opencsv to dump the ResultSet to CSV.

dynamic SQL execution and saving the result in flat file in SSIS

I want to create a SSIS package which writes a file with data generated by executing a SQL Statement. This generic package will be invoked by other packages passing in correct SQL as a variable.
Thus in the generic package :
I want to execute a dynamic SELECT query and fetch dynamic number of columns from a single database instance, the connection string does not per call and store the result into a flat file.
What would be an ideal way to accomplish this in SSIS.
What I tried :
The simplest solution that I could find was a writing a script task which would open a SQL connection , execute the SQL using SQLCommand, populate a datatable using the data fetched and write the contents directly to the file system using System.io.File and Release the connection.
I tried using OLE Database source with the SQLsupplied by a variable (with Validation set to false) and directing the rows into a Flat file connection. However due to the dynamic number and names of the columns I ran into errors.
Is there a more standard way of achieving this without using a script task?
How about this ... concatenate all field values into one field, and map AllFields to a field in a text file destination.
SELECT [f1]+',' + [f2] AS AllFields FROM [dbo].[A]
All of the "other"packages will know how to create the correct SQL. Their only contract with the "generic" package would be to eventually have only one field nameed "AllFields".
To answer your question directly, I do not think there is a "standard" way to do this. I believe the solution from Anoop would work well and while I have not tested the idea I wish I would have investigated it before writing my own solution. You should not need a script task in that solution...
In any case, I did write my own way to generate csv files from SQL tables that may run up against edge cases and need polishing but works rather well right now. I am looping through multiple tables before this task so the CurrentTable variable can be replaced with any variable you want.
Here is my code:
public void Main()
{
string datetime = DateTime.Now.ToString("yyyyMMddHHmmss");
try
{
string TableName = Dts.Variables["User::CurrentTable"].Value.ToString();
string FileDelimiter = ",";
string TextQualifier = "\"";
string FileExtension = ".csv";
//USE ADO.NET Connection from SSIS Package to get data from table
SqlConnection myADONETConnection = new SqlConnection();
myADONETConnection = (SqlConnection)(Dts.Connections["connection manager name"].AcquireConnection(Dts.Transaction) as SqlConnection);
//Read data from table or view to data table
string query = "Select * From [" + TableName + "]";
SqlCommand cmd = new SqlCommand(query, myADONETConnection);
//myADONETConnection.Open();
DataTable d_table = new DataTable();
d_table.Load(cmd.ExecuteReader());
//myADONETConnection.Close();
string FileFullPath = Dts.Variables["$Project::ExcelToCsvFolder"].Value.ToString() + "\\Output\\" + TableName + FileExtension;
StreamWriter sw = null;
sw = new StreamWriter(FileFullPath, false);
// Write the Header Row to File
int ColumnCount = d_table.Columns.Count;
for (int ic = 0; ic < ColumnCount; ic++)
{
sw.Write(TextQualifier + d_table.Columns[ic] + TextQualifier);
if (ic < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
// Write All Rows to the File
foreach (DataRow dr in d_table.Rows)
{
for (int ir = 0; ir < ColumnCount; ir++)
{
if (!Convert.IsDBNull(dr[ir]))
{
sw.Write(TextQualifier + dr[ir].ToString() + TextQualifier);
}
if (ir < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
}
sw.Close();
Dts.TaskResult = (int)ScriptResults.Success;
}
catch (Exception exception)
{
// Create Log File for Errors
//using (StreamWriter sw = File.CreateText(Dts.Variables["User::LogFolder"].Value.ToString() + "\\" +
// "ErrorLog_" + datetime + ".log"))
//{
// sw.WriteLine(exception.ToString());
//}
Dts.TaskResult = (int)ScriptResults.Failure;
throw;
}
Dts.TaskResult = (int)ScriptResults.Success;