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.
Related
String Post_Code = "CREATE TABLE IF NOT EXISTS PostCode("
+ "PostCode_ID integer PRIMARY KEY, "
+ "Code string NOT NULL, "
+ "City_ID integer,"
+ "FOREIGN KEY (City_ID)"
+ "REFERENCES City (City_ID)"
+ "ON UPDATE CASCADE "
+ "ON DELETE SET NULL, "
+ "County_ID integer,"
+ "FOREIGN KEY (County_ID)"
+ "REFERENCES County (County_ID)"
+ "ON UPDATE CASCADE "
+ "ON DELETE SET NULL"
+ ");";
I believe it's most likely to be something within the first foreign key reference.
Either move all the FOREIGN KEY definitions at the end of the statement:
CREATE TABLE IF NOT EXISTS PostCode(
PostCode_ID integer PRIMARY KEY,
Code TEXT NOT NULL,
City_ID integer,
County_ID integer,
FOREIGN KEY (City_ID) REFERENCES City (City_ID) ON UPDATE CASCADE ON DELETE SET NULL,
FOREIGN KEY (County_ID)REFERENCES County (County_ID) ON UPDATE CASCADE ON DELETE SET NULL
);
or, define each foreign key right after the definition of each column without the FOREIGN KEY keywords:
CREATE TABLE IF NOT EXISTS PostCode(
PostCode_ID integer PRIMARY KEY,
Code TEXT NOT NULL,
City_ID integer REFERENCES City (City_ID) ON UPDATE CASCADE ON DELETE SET NULL,
County_ID integer REFERENCES County (County_ID) ON UPDATE CASCADE ON DELETE SET NULL
);
See the demo.
Note that there is no string data type in SQLite.
I changed it to TEXT.
I am trying to create the following tables design but I am getting this error below how can I set the foreign key for the stops table in the arrivaltimes table?
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FOREIGN KEY REFERENCES stops(stop_id) )' at line 4
stt.execute("CREATE TABLE IF NOT EXISTS stops"
+ "(stop_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, "
+ " name varchar(30) NOT NULL, " + " route INT(11) NOT NULL, "
+ " lat double(10,6) NOT NULL, "
+ " longi double(10,6)NOT NULL) ");
stt.execute("CREATE TABLE IF NOT EXISTS arrivaltimes(id INT(11) NOT NULL PRIMARY KEY,"
+ " weekday VARCHAR(20) NOT NULL,"
+ "arrivaltime time NOT NULL,"
+ " stop_id INT FOREIGN KEY REFERENCES stops(stop_id) )" );
Change
stop_id INT FOREIGN KEY REFERENCES stops(stop_id)
to
stop_id INT, FOREIGN KEY fk_stop_id(stop_id) REFERENCES stops(stop_id)
I have updated the query, please take note of the syntax of the FOREIGN KEY, where you had an error. Cheers!
stt.execute("CREATE TABLE IF NOT EXISTS stops"
+ "(stop_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, "
+ " name varchar(30) NOT NULL, " + " route INT(11) NOT NULL, "
+ " lat double(10,6) NOT NULL, "
+ " longi double(10,6)NOT NULL) ");
stt.execute("CREATE TABLE IF NOT EXISTS arrivaltimes(id INT(11) NOT NULL PRIMARY KEY,"
+ " weekday VARCHAR(20) NOT NULL,"
+ "arrivaltime time NOT NULL,"
+ " FOREIGN KEY (stop_id) REFERENCES stops(stop_id) )" );
If you look at the MySQL CREATE TABLE syntax, then you have the choice between:
An inline definition (note the absence of FOREIGN KEY)
stop_id INT REFERENCES stops(stop_id)
and an explicit definition:
stop_id INT,
FOREIGN KEY (stop_id) REFERENCES stops(stop_id)
or better (with named constraint):
stop_id INT,
CONSTRAINT fk_arrivaltimes_stops FOREIGN KEY (stop_id) REFERENCES stops(stop_id)
I have a blob in my database table. If I select 10 rows of the table (each row containing 1 blob), it takes 300 milliseconds.
However, if I select 15 rows, it takes 20 seconds. I don't understand what is going on. The file that is selected is an image of 1 MB.
public void find() throws SQLException, IOException {
ResultSet rs = stm.executeQuery();
while (rs.next()) {
FileOutputStream output = new FileOutputStream(new File(
"C:\\Users\\test\\test.jpg"));
InputStream input = rs.getBinaryStream("photo");
byte[] buffer = new byte[8192];
int count = 0;
while ((count = input.read(buffer)) > 0) {
output.write(buffer, 0, count);
}
}
}
I honestly don't know why such small difference takes up so much time.
Any help is greatly appreciated.
Edit for extra notes:
Yes, the overwriting of the same image is intentional. (sorry for not pointing that out)
Using rs.getBlob("photo").getBinaryStream() has still the same effect.
The execution time of the method find() is being benchmarked via JMH. The piece of code above remains the same.
The exact same code and SQL is running for a 'contact' table that for the first test has 100 rows (of which 10 are selected) and the other 150 rows (of which 15 are selected).
The blob is inside the contact table.
The SQL:
String query = "SELECT * FROM contact c INNER JOIN contact_address ca ON c.id=ca.contact_id INNER JOIN groups_contact gc ON gc.contact_id=c.id INNER JOIN groups gr WHERE ca.country=? AND gr.name=? GROUP by c.id";
stm = conn.prepareStatement(query);
stm.setString(1, "NL");
stm.setString(2, "Friends");
stm.addBatch();
Update:
(measuring method is modified please see the above)
Selecting 10 rows: 239 ms.
Selecting 15 rows: 26378 ms.
Selecting 25 rows: 34888 ms.
Selecting 50 rows: 73267 ms.
Selecting 75 rows: 81885 ms.
Selecting 100 rows: 106528 ms.
Creations of table:
String createUserTable = "CREATE TABLE User (id INTEGER not NULL AUTO_INCREMENT, email VARCHAR(255), password VARCHAR(255), PRIMARY KEY (id))";
String createGroupTable = "CREATE TABLE Groups (id INTEGER not NULL AUTO_INCREMENT , name VARCHAR(255), user_id INTEGER not NULL, PRIMARY KEY (id), FOREIGN KEY (user_id) REFERENCES User(id))";
String createContactTable = "CREATE TABLE Contact (id INTEGER not NULL AUTO_INCREMENT , firstname VARCHAR(255), lastname VARCHAR(255), note VARCHAR(255), photo MEDIUMBLOB, user_id INTEGER, PRIMARY KEY (id), FOREIGN KEY (user_id) REFERENCES User(id))";
String createGroupContactTable = "CREATE TABLE Groups_Contact (id INTEGER not NULL AUTO_INCREMENT, contact_id INTEGER not NULL, group_id INTEGER not NULL, PRIMARY KEY (id), FOREIGN KEY (contact_id) REFERENCES Contact(id), FOREIGN KEY (group_id) REFERENCES Groups(id))";
String createContactAddressTable = "CREATE TABLE Contact_Address (id INTEGER not NULL AUTO_INCREMENT , street VARCHAR(255), number INTEGER, zipcode VARCHAR(255), city VARCHAR(255), country VARCHAR(255), addresstype VARCHAR(255), contact_id INTEGER not null, PRIMARY KEY (id), FOREIGN KEY (contact_id) REFERENCES Contact(id))";
String createContactPhoneTable = "CREATE TABLE Contact_Phone (id INTEGER not NULL AUTO_INCREMENT , type VARCHAR(255), number VARCHAR(255), contact_id INTEGER not null, PRIMARY KEY (id), FOREIGN KEY (contact_id) REFERENCES Contact(id))";
String createContactEmailTable = "CREATE TABLE Contact_Email (id INTEGER not NULL AUTO_INCREMENT , type VARCHAR(255), email VARCHAR(255), contact_id INTEGER not null, PRIMARY KEY (id), FOREIGN KEY (contact_id) REFERENCES Contact(id))";
Are you sure its not the joins? Some joins can be very slow, especially multiple joins. Often we had to run separate queries because joins might slow a query down.
Also what kind of indexes do you have?
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
I'm testing the foreign keys in Android and I have problems I don't understand:
To create the tables (with hard-coded values)
db.execSQL("CREATE TABLE IF NOT EXISTS table_A ( " +
"_id long primary key , value1 long );");
db.execSQL("CREATE TABLE IF NOT EXISTS table_B ( " +
"_id long primary key , value1fk long , value2 long,"+
"FOREIGN KEY (value1fk) REFERENCES table_A (value1) ON DELETE CASCADE);");
then I execute:
ContentValues values = new ContentValues();
values.put("_id", 1);
values.put("value1", 200);
long result = mDb.insert("table_A", null, values);
Log.e("","done (" + result + ")");
values = new ContentValues();
values.put("_id", 1);
values.put("value1fk", 200);
values.put("value2", 10);
result= mDb.insert("table_B", null, values);
Log.e("","done (" + result + ")");
The output is
done(1)
done(-1)
Giving the second insert an foreign key mismatch
E/SQLiteDatabase(25476): Error inserting _id=1 value1fk=200 value2=10
E/SQLiteDatabase(25476): android.database.sqlite.SQLiteException: foreign key mismatch: , while compiling: INSERT INTO table_B(_id,value1fk,value2) VALUES (?,?,?)
Why is that happening?
According to sqlite documentation on foreign keys
http://www.sqlite.org/foreignkeys.html
you need to either :
use the primary key as your foreign key
FOREIGN KEY (value1fk) REFERENCES table_A (_id)
use a Unique column as a foreign key
CREATE TABLE IF NOT EXISTS table_A (_id long primary key , value1 long UNIQUE);
The value_1 field in table_A is not the primary key. Shouldn't it be
FOREIGN KEY (value1fk) REFERENCES table_A (_id)...
instead?