Creating tables in DB results in a lot of exceptions - java

I'm fairly new to SQL and Java so bear with me.
I am trying to reach my DB, create some tables, set it to InnoDB and set some Foreign Keys.
Everything compiles and looks okay, but I end up getting these errors (seems to be located in the JDBC lib):
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'Auditorium'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:377)
at com.mysql.jdbc.Util.getInstance(Util.java:360)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:978)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3887)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3823)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2526)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2484)
at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:848)
at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:742)
at CreateDB.createTables(CreateDB.java:35)
at Main.main(Main.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
CreateDB.java class looks like this:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import static java.sql.DriverManager.registerDriver;
public class CreateDB {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String database_name = "<DBname>";
static final String DB_URL = "<server>" + "<DBname>";
static final String USER = "*****";
static final String PASS = "*****";
Statement statement = null;
Connection connection = null;
public CreateDB()
{
try {
registerDriver(new com.mysql.jdbc.Driver());
connection = DriverManager.getConnection(DB_URL, USER, PASS);
statement = connection.createStatement();
} catch (Exception e) {
e.printStackTrace(); // handle errors
}
}
public void createTables() throws SQLException {
statement.execute("DROP TABLE Auditorium");
statement.execute("DROP TABLE Customer");
statement.execute("DROP TABLE Screening");
statement.execute("DROP TABLE Ticket");
String Auditorium = "CREATE TABLE Auditorium " //Sets name and size of each auditorium
+ "(ID INTEGER NOT NULL AUTO_INCREMENT, " //Primary key for Auditorium
+ "Name VARCHAR(10), " //Name for specific Auditorium (example: 'aud1')
+ "Row INTEGER NOT NULL, " //Amount of rows in specific auditorium
+ "Column INTEGER NOT NULL, " //Amount of columns in specific auditorium
+ "PRIMARY KEY (ID));"; //Sets primary key (ID)
String Screening = "CREATE TABLE Screening " //Keeps track of what screenings we offer
+ "(ID INTEGER NOT NULL AUTO_INCREMENT, " //Primary key for Screening
+ "Auditorium VARCHAR(10) NOT NULL, " //Name for specific Auditorium (example: 'aud1')
+ "Movie VARCHAR(50) NOT NULL, " //Movie title
+ "Date DATE NOT NULL, " //Specific date the movie is being shown
+ "Time TIME NOT NULL, " //What time the movie runs
+ "PRIMARY KEY (ID));"; //Sets primary key (ID)
String Customer = "CREATE TABLE Customer " //Information on the customer
+ "(ID INTEGER NOT NULL AUTO_INCREMENT, " //Primary key for Customer
+ "Name VARCHAR(50) NOT NULL, " //Name on customer
+ "Phone INTEGER NOT NULL, " //Phone on customer
+ "Email VARCHAR(50), " //Optional mail on customer
+ "PRIMARY KEY (ID);"; //Sets primary key (ID)
String Ticket = "CREATE TABLE Ticket " //Ticket that customer can buy
+ "(ID INTEGER NOT NULL AUTO_INCREMENT, " //Primary key for Ticket
+ "Row INTEGER NOT NULL, " //Specific row
+ "Seat INTEGER NOT NULL, " //Specific seat
+ "AudID INTEGER NOT NULL, " //Foreign key references Auditorium(ID)
+ "ScreeningID INTEGER NOT NULL, " //Foreign key references Screening(ID)
+ "PRIMARY KEY (ID);"; //Sets primary key (ID)
statement.executeUpdate(Auditorium);
statement.executeUpdate(Screening);
statement.executeUpdate(Customer);
statement.executeUpdate(Ticket);
}
public void changeEngine() throws SQLException {
String Auditorium = "ALTER TABLE Auditorium ENGINE=InnoDB;";
String Screening = "ALTER TABLE Screening ENGINE=InnoDB;";
String Customer = "ALTER TABLE Customer ENGINE=InnoDB;";
String Ticket = "ALTER TABLE Ticket ENGINE=InnoDB;";
statement.execute(Auditorium);
statement.execute(Screening);
statement.execute(Customer);
statement.execute(Ticket);
}
public void applyForeignKeys() throws SQLException {
String AudID = "ALTER TABLE Ticket ADD FOREIGN KEY (AudID) REFERENCES Auditorium(ID);";
String ScreeningID = "ALTER TABLE Ticket ADD FOREIGN KEY (ScreeningID) REFERENCES Screening(ID);";
statement.executeUpdate(AudID);
statement.executeUpdate(ScreeningID);
}
}
My main method is very simply doing so:
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws SQLException {
CreateDB c = new CreateDB();
c.createTables();
c.changeEngine();
c.applyForeignKeys();
}
}

The line in the stacktrace:
at CreateDB.createTables(CreateDB.java:35)
Tells you the line in you code that the error occurs at.
My guess is that line 35 is:
statement.execute("DROP TABLE Auditorium");
You can't drop a table that doesn't exist.
Try:
statement.execute("DROP TABLE IF EXISTS Auditorium");

I think the problem is that you call c.createTables() first in your main method and the tables don't exist.
If the tables don't exist then an error will be returned, such as table does not exits because you try to run a drop statement on non-existant tables.
Modify createTables() to not run DROP statements if the tables don't exist.
Since you are using mysql you can do this:
statement.execute("DROP TABLE IF EXISTS Auditorium");
For Oracle or other databases it would be different.

You also forgot a ) at the end of the strings in the following statements:
String Customer = "CREATE TABLE Customer " //Information on the customer
+ "(ID INTEGER NOT NULL AUTO_INCREMENT, " //Primary key for Customer
+ "Name VARCHAR(50) NOT NULL, " //Name on customer
+ "Phone INTEGER NOT NULL, " //Phone on customer
+ "Email VARCHAR(50), " //Optional mail on customer
+ "PRIMARY KEY (ID);"; //Sets primary key (ID)
String Ticket = "CREATE TABLE Ticket " //Ticket that customer can buy
+ "(ID INTEGER NOT NULL AUTO_INCREMENT, " //Primary key for Ticket
+ "Row INTEGER NOT NULL, " //Specific row
+ "Seat INTEGER NOT NULL, " //Specific seat
+ "AudID INTEGER NOT NULL, " //Foreign key references Auditorium(ID)
+ "ScreeningID INTEGER NOT NULL, " //Foreign key references Screening(ID)
+ "PRIMARY KEY (ID);";

statement.execute("DROP TABLE IF EXISTS Auditorium");

In most database engines, there are reserved words which must be marked up in a particular fashion to be used as object names (i.e. table or field names). In MySql, row and column are reserved words.
Enclosing the column name in backticks will allow a keyword to be used as a column name.

Related

"Missing columns in relationship" when creating table

I have tried to create three tables(CUSTOMERS, VEHICLES and RENTALS), the third table (RENTALS) has foreign keys referring to the two primary keys of the first two tables (CUSTOMERS and RENTALS). When creating this third table I get an error Missing columns in relationship(Rel=CUSTOMERS[[]] -> RENTALS[[]])
Here's my codes
private void createTables() throws SQLException {
Statement statement = conn.createStatement();
statement.executeUpdate("CREATE TABLE CUSTOMERS(custNumber AUTOINCREMENT PRIMARY KEY, " +
"firstName VARCHAR(155) NOT NULL, surname VARCHAR(155) NOT NULL, idNum INTEGER NOT NULL, phoneNum INTEGER NOT NULL, canRent BIT NOT NULL)");
statement.executeUpdate("CREATE TABLE VEHICLES(vehNumber AUTOINCREMENT PRIMARY KEY, make VARCHAR(155) NOT NULL, " +
"category VARCHAR(155) NOT NULL, rentalPrice FLOAT NOT NULL, availableForRent BIT NOT NULL)");
statement.executeUpdate("CREATE TABLE RENTALS(rentalNumber AUTOINCREMENT PRIMARY KEY, dateRental VARCHAR(155) NOT NULL, dateReturned VARCHAR(155) NOT NULL, " +
"pricePerDay FLOAT NOT NULL, totalRental FLOAT NOT NULL, custNumber INTEGER FOREIGN KEY REFERENCES CUSTOMERS(custNumber), " +
"vehNumber INTEGER FOREIGN KEY REFERENCES VEHICLES(vehNumber))");
System.out.println("Database populated");
}
and here's the error
Your help will be very much appreciated, I have looked around but found nothing that helps.
In Access, an AutoNumber field (DDL: AUTOINCREMENT or COUNTER) is a "Long Integer".
In UCanAccess DDL, INTEGER creates an "Integer" (16-bit) field and LONG creates a "Long Integer" (32-bit) field.
You need to declare your foreign key columns as LONG, not INTEGER.

Why is sqlite auto_increment not incrementing?

I've got a database set up to store notes. I want to auto increment the first column. I've tried this, but when I read from the database every result in that column is 'null'.This is the code for creating the DB.
private static final String NOTES_TABLE_CREATE =
"CREATE TABLE " + NOTES_TABLE_NAME + " (" +
COLUMN_NAMES[0] + " INTEGER AUTO_INCREMENT, " +
COLUMN_NAMES[1] + " TEXT, " +
COLUMN_NAMES[2] + " TEXT, " +
COLUMN_NAMES[3] + " TEXT, " +
COLUMN_NAMES[4] + " TEXT, " +
COLUMN_NAMES[5] + " TEXT, " +
COLUMN_NAMES[6] + " TEXT);";
This is the code for getting the DB result.
SQLiteDatabase db = this.getReadableDatabase();
Cursor result = db.query(NOTES_TABLE_NAME, COLUMN_NAMES, null, null, null, null, null, null);
result.moveToFirst();
result.moveToNext();
System.out.println(result.getInt(0));
System.out.println(result.getString(1));
This is the output from logcat
04-09 17:56:17.981 22147-22147/com.example.a8460p.locationotes I/System.out: 0
04-09 17:56:17.981 22147-22147/com.example.a8460p.locationotes I/System.out: notetitle1234567890
AUTO_INCREMENT (as opposed to INTEGER PRIMARY KEY AUTOINCREMENT) is not supported in sqlite.
This is a little non-obvious, because sqlite silently ignores column constraints it does not recognize:
sqlite> CREATE TABLE test (
a INTEGER FABBELBABBEL NOT NULL
);
sqlite> .schema test
CREATE TABLE test (a INTEGER FABBELBABBEL NOT NULL);
sqlite> INSERT INTO test (a) VALUES (1);
sqlite> INSERT INTO test (a) VALUES (NULL);
Error: NOT NULL constraint failed: test.a
AUTOINCREMENT on the other hand, is supported for integer primary keys and only there, so the obvious workaround attempt is not supported, either:
sqlite> CREATE TABLE test (a INTEGER AUTOINCREMENT NOT NULL, b INTEGER);
Error: near "AUTOINCREMENT": syntax error
In short: Auto increment is only available for integer primary keys.

Insert into table with autoincrement primary key

I'm creating a table as follows:
#Override
public void onCreate(SQLiteDatabase db) {
String sql =
"CREATE TABLE IF NOT EXISTS users (" +
"_id INTEGER PRIMARY KEY, " +
"name TEXT NOT NULL, " +
"password TEXT NOT NULL);";
db.execSQL(sql);
sql = "INSERT INTO users VALUES ('testuser', 'textpassword')";
db.execSQL(sql);
}
But when I try to insert a user, I'm getting the following exception:
android.database.sqlite.SQLiteException: table users has 3 columns but 2 values were supplied (code 1): , while compiling: INSERT INTO users VALUES ('testuser', 'textpassword')
As _id is the primarykey, why is it expecting it? I also tried AUTOINCREMENT but it doesn't work.
Try this
#Override
public void onCreate(SQLiteDatabase db) {
String sql =
"CREATE TABLE IF NOT EXISTS users (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
"name TEXT NOT NULL, " +
"password TEXT NOT NULL);";
db.execSQL(sql);
sql = "INSERT INTO users(name, password) VALUES ('testuser', 'textpassword')";
db.execSQL(sql);
}
AUTOINCREMENT NOT NULL is missing in your insert query which will increase the value of _id field automatically.
You should specify the values you're inserting:
sql = "INSERT INTO users(name, password) VALUES ('testuser', 'textpassword')";
There's no need to specify AUTOINCREMENT: On an INSERT, if the ROWID or INTEGER PRIMARY KEY column is not explicitly given a value, then it will be filled automatically with an unused integer, usually one more than the largest ROWID currently in use. This is true regardless of whether or not the AUTOINCREMENT keyword is used.

JDBC Auto Increment

I am trying to create table that has column that auto increments the user id column. When I use the below code I get this error:
Exception in thread "main" java.sql.SQLSyntaxErrorException: ORA-00907: missing right parenthesis
String sql = "CREATE TABLE DBUSER("
+ "USER_ID NUMBER(5) NOT NULL AUTO_INCREMENT, "
+ "USERNAME VARCHAR(20) NOT NULL, "
+ "CREATED_BY VARCHAR(20) NOT NULL, "
+ "CREATED_DATE DATE NOT NULL, " + "PRIMARY KEY (USER_ID) "
+ ")"; Statement stmt;
stmt = connection.createStatement();
stmt.executeUpdate(sql);
It should work if you remove the auto-increment
CREATE TABLE DBUSER(
USER_ID NUMBER(5) NOT NULL,
USERNAME VARCHAR(20) NOT NULL,
CREATED_BY VARCHAR(20) NOT NULL,
CREATED_DATE DATE NOT NULL,
PRIMARY KEY (USER_ID)
)
Auto increment is not supported in Oracle

Compare an SQL file to an existing database table with Java

I am writing a bit of Java (1.7) code to test a given database table against a given sql file. What I would like is a way to turn my sql file into a java object, then test the db field names and field types are the same as the file backed object.
An example sql file looks like this:
create table foo (
id int not null auto_increment,
term_id varchar(128) not null,
term_name varchar(255) not null,
parent_id varchar(128) not null,
parent_name varchar(255),
top_term_flag varchar(5),
primary key (id)
);
create index foo_pn on foo ( parent_name );
create index foo_ttf on foo ( top_term_flag );
And the part of my Java program to do this check looks like this:
// Step 1, confirm the table exists
// Database and table tests
DatabaseMetaData dbm = connection.getMetaData();
// check if "this.dbtable" exists.
// The ToUpperCase covers Oracle
ResultSet tables = dbm.getTables(null, null, this.dbtable.toUpperCase(), null);
if (tables.next()) {
// Table exists
log.info("Table: {} exists!", this.dbtable);
// Step 2, get each field and test against the file
ResultSet columns = dbm.getColumns(null, null, this.dbtable, null);
while ( columns.next()) {
String name = columns.getString(4); // this gets the column name
-> Now what? <-
}
}
I've looked at Spring JDBCTestUnit and Flyway, but they don't seem to provide the functionality I need.
Thank you.
Update:
I understand I can also use Hibernate to generate my Java classes that represent my sql file and then test the DB table against those. Does any one have a sample for how to get this done?
Using JSqlParser 0.8.8 from https://github.com/JSQLParser/JSqlParser.
Here is a parsing example to get column names, table name, types. As a result you get a hierarchy of java objects from your sqls.
public class CheckSQLs {
public static void main(String[] args) throws JSQLParserException {
String sqls = "create table foo (\n"
+ " id int not null auto_increment,\n"
+ " term_id varchar(128) not null,\n"
+ " term_name varchar(255) not null,\n"
+ " parent_id varchar(128) not null,\n"
+ " parent_name varchar(255),\n"
+ " top_term_flag varchar(5),\n"
+ " primary key (id)\n"
+ ");\n"
+ "create index foo_pn on foo( parent_name );\n"
+ "create index foo_ttf on foo ( top_term_flag );";
for (String sql : sqls.split(";")) {
Statement parse = CCJSqlParserUtil.parse(sql);
System.out.println(parse);
if (parse instanceof CreateTable) {
CreateTable ct = (CreateTable)parse;
System.out.println("table=" + ct.getTable().getFullyQualifiedName());
for (ColumnDefinition colDef : ct.getColumnDefinitions()) {
System.out.println("column=" + colDef.getColumnName() + " " + colDef.getColDataType() + " " + colDef.getColumnSpecStrings());
}
}
}
}
}
This runs with the output:
CREATE TABLE foo (id int not null auto_increment, term_id varchar (128) not null, term_name varchar (255) not null, parent_id varchar (128) not null, parent_name varchar (255), top_term_flag varchar (5), primary key (id))
table=foo
column=id int [not, null, auto_increment]
column=term_id varchar (128) [not, null]
column=term_name varchar (255) [not, null]
column=parent_id varchar (128) [not, null]
column=parent_name varchar (255) null
column=top_term_flag varchar (5) null
Now you could use this object to validate against your database.
If the SQL file syntax doesn't vary much from your example, you could write a simple parser to read the file and generate your java object: table plus list of fields/types and indexes
"tablename" always comes after "create table"
the field names and types always come after that
indexes after that
Or there are parsers available:
jsqlparser
http://jsqlparser.sourceforge.net/
Other questions on this site cover some of the same ground
SQL parser library for Java

Categories