Insert into table with autoincrement primary key - java

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.

Related

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.

How to Insert a value where not exist in SQLite Android

I want to insert values into my table only when values don't exist in the table.
String CREATETABLE = "CREATE TABLE contacts ( " +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT, "+
"phone TEXT )";
Here is my code to create the table, I used UNIQUE(phone), and it doesn't work.
And to add a new contact I am using this code:
ContentValues values = new ContentValues();
values.put("name", contact.getName()); // get title
values.put("phone", contact.getNumero()); // get author
// 3. insert
db.insert("contacts", // table
null, //nullColumnHack
values);
I don't think there is a way of doing that without retrieving the row first. You query the database looking for that particular contact (which you have to specify at least one column to be unique, or any combination of columns to be primary key) otherwise how would you handle two person with the same name?.
So you query and search for the desired person, if you find it, check if the column is null and a) insert if it is, b) ignore if it isn't. If the query doesn't find any person, you cant just insert.
About the unique constraint, its like this:
String CREATETABLE = "CREATE TABLE contacts ( " +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT, " +
"phone TEXT UNIQUE)";
In your sample you are using SQLiteDatabase.insert(), try to use SQLiteDatabase.insertWithOnConflict() with one of values CONFLICT_IGNORE, CONFLICT_REPLACE or others.
Also have a look about implementing database as ContentProvider which is much harder to understand but really good to know.

Creating tables in DB results in a lot of exceptions

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.

Android SQLite ordering table columns differently

I'm setting up an SQLite Database and I've got most things set up how I think they're supposed to be. The main error has to with a column not being where it should be. I initialized the database column names in strings like so:
public static final String KEY_ROWID = "_id";
public static final String KEY_SPORT = "given_sport";
public static final String KEY_NAME = "given_name";
public static final String KEY_DATE = "given_date";
public static final String KEY_TIME = "given_time";
public static final String KEY_PERIOD = "given_period";
public static final String KEY_LOCATION = "given_location";
When it was time to create a table with the column names:
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
KEY_SPORT + " TEXT NOT NULL, " +
KEY_NAME + " TEXT NOT NULL, " +
KEY_DATE + " TEXT NOT NULL, " +
KEY_TIME + " TEXT NOT NULL, " +
KEY_PERIOD + " TEXT NOT NULL, " +
KEY_LOCATION + "TEXT NOT NULL);"
);
The problem now is that I'm getting the following error:
05-27 04:13:01.448: E/Database(273): android.database.sqlite.SQLiteException: table groupTable has no column named given_location: , while compiling: INSERT INTO groupTable(given_location, given_time, given_date, given_period, given_sport, given_name) VALUES(?, ?, ?, ?, ?, ?);
It seems like the table names are being reordered and that's what is causing the error in insertion. I'm clueless though and I'd really appreciate some help with this.
EDIT: here's the INSERT command
ContentValues cv = new ContentValues();
cv.put(KEY_SPORT, sportInput);
cv.put(KEY_NAME, nameInput);
cv.put(KEY_DATE, dateInput);
cv.put(KEY_TIME, timeInput);
cv.put(KEY_PERIOD, periodInput);
cv.put(KEY_LOCATION, locationInput);
return dbSQL.insert(DATABASE_TABLE, null, cv);
The problem is probably that you've changed the database structure but not the database version. It's a weird issue that I had to spend a lot of time figuring out the first time.
In your DatabaseHelper class there should be a version number, just increment it by one anytime you change any table schema etc.
EDIT
You're missing a space before the "TEXT" in your SQL table creation.
It should be:
...
+ KEY_LOCATION+ " TEXT" ...
once you fix that, increment the version number again.
The order of the table columns will not create "no column" error. If you have added the column to your table after running your app at least once but haven't incremented the database version, this is one way to cause this error.
The order of these columns:
INSERT INTO groupTable(given_location, given_time, given_date, given_period, given_sport, given_name) ...
depends on the order of the columns when you write your INSERT statement, it is not a fixed order based off of the CREATE command.

Android Sqlite and foreign keys failing

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?

Categories