My question is that it is possible to know a field is primary key of table by looking cursor. Or how can we learn which field is primary key?
I want write a class like that. So I must learn it programatically
public class BO {
private HashMap<String, Object> data;
private String primaryKey="";
public BO() {
data=new HashMap<String, Object>();
}
public String getUpdateQuery() {
return null;
}
public String getInsertQusery() {
return null;
}
public String getPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(String primaryKey) {
this.primaryKey = primaryKey;
}
public int getLogicalReference() {
return logicalReference;
}
public void loadDataFromCursor(Cursor cur){
String[] fields=cur.getColumnNames();
for(int i=0;i<fields.length;i++){
switch (cur.getType(i)) {
case Cursor.FIELD_TYPE_INTEGER:
data.put(fields[i], cur.getInt(i));
break;
default:
break;
}
}
}
public void setLogicalReference(int logicalReference) {
this.logicalReference = logicalReference;
}
}
Just like CL. said in his comment, I believe a Cursor does not hold this information. Whether a column holds a primary key is related to the table structure, which is different from the content of the table. A Cursor is used to access data and not give information about the table's structure.
Besides, the Cursor interface in Android is not necessarily related to a SQLiteDatabase, so you should not be able to get this kind of information from it.
However, I can't think of any good usage case where this should be really useful. Maybe some kind of far-fetched genericity of the code; in any case, there is a good chance you should rethink your design (or explain it if you really think it's correct; in that case, I'm curious !)
Here is an example using Python and Mysql.
pkey = cursor.execute("SHOW KEYS FROM " + tablename + " WHERE Key_name = 'PRIMARY'")
And the Use Case :
Query = "INSERT INTO table " + str(tuple(table[0].keys()))
Query += "\nVALUES\n"
Query += str(tuple(table[0].values()))
Query += "\nON DUPLICATE KEY UPDATE\n"
for key in table[0].keys():
if not key in pkey:
Query += key + " = VALUES(" + key + "),\n"
Query = Query.rstrip(",")
cursor.execute(Query)
The resulting string would Insert or Update the table. If you try to push the Primary Key to the table you throw an error of Duplicate Primary. My program is parsing a directory of JSON files and importing them into database as part of an API retrieval process. I am pulling data from 3 different API's and would like to keep the code generic so that I can re-use it.
I am less familiar with SQLLite, however you could implement something that would do this for you, by naming your primary key with something that indicated it was a primary key : pk_id for example and then just parsing the name of the field to find if it contains pk.
Related
I have got the error message " or expected, got 'Index'" when I was trying to create a table and I do not really understand why is the code expecting a column definition or table constraint at this line
I have tried with changing the whitespaces, however that only change the place where the error is prompted. The content of the error message does not change
This is the part that I have declared the strings
public class TaskEntry implements BaseColumns {
public static final String TABLE = "Users";
public static final String INDEX = "Index";
public static final String COL_TASK_TITLE = "title";
}
The following is my code for the creating table part
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE " + Item_contract.TaskEntry.TABLE + " ( " +
Item_contract.TaskEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
Item_contract.TaskEntry.INDEX + " INTEGER NOT NULL, " +
Item_contract.TaskEntry.COL_TASK_TITLE + " TEXT NOT NULL" + ");";
db.execSQL(createTable);
}
You cannot use INDEX as a column name as it is a keyword.
The SQL standard specifies a large number of keywords which may not be
used as the names of tables, indices, columns, databases, user-defined
functions, collations, virtual table modules, or any other named
object. The list of keywords is so long that few people can remember
them all. For most SQL code, your safest bet is to never use any
English language word as the name of a user-defined object.
SQL As Understood By SQLite - SQLite Keywords
So change
public static final String INDEX = "Index";
perhaps to
public static final String INDEX = "IX";
You could enclose the column name if you really wanted it to be INDEX e.g.
public static final String INDEX = "[Index]";
As per :-
If you want to use a keyword as a name, you need to quote it. There are four ways of quoting keywords in SQLite:
'keyword' A keyword in single quotes is a string literal.
"keyword" A keyword in double-quotes is an identifier.
[keyword] A keyword enclosed in square brackets is an identifier. This is not standard SQL. This quoting mechanism is used by MS Access and SQL Server and is included in SQLite for compatibility.
`keyword` A keyword enclosed in grave accents (ASCII code 96) is an identifier. This is not standard SQL. This quoting mechanism is used by MySQL and is included in SQLite for compatibility.
SQL As Understood By SQLite - SQLite Keywords
Note
You will have to do one of the following to get the onCreate method to run and thus alter the schema:-
Delete the App's data.
Uninstall the App.
I need to get data from two tables in Android. I am using OrmLite for the database.
My query is next:
SELECT m.*, r.campaign_name, r.description, r.terms_condition
FROM mycampaignlist m, redeemlanguagedata r
WHERE r.lang_type = 2
How could I create this type of query in OrmLite.
I need to get data from two tables in Android... How could I create this type of query in OrmLite.
ORMLite does not support JOIN queries using the internal QueryBuilder if you are selecting a combination of fields from each table. In your example, you have some fields from mycampaignlist and some from redeemlanguagedata so ORMLite can't return a object without more help.
I'd recommend using the raw queries functionality and then you can get the output as a List<String[]>, List<Object[]> if you specify the data-types, or as a list of your own objects if you specify a RawRowMapper<Foo>.
For example, to quote from the docs:
GenericRawResults<Foo> rawResults = orderDao.queryRaw(
"SELECT account_id,sum(amount) FROM orders GROUP BY account_id",
new RawRowMapper<Foo>() {
public Foo mapRow(String[] columnNames,
String[] resultColumns) {
return new Foo(Long.parseLong(resultColumns[0]),
Integer.parseInt(resultColumns[1]));
}
});
// page through the results
for (Foo foo : rawResults) {
System.out.println("Account-id " + foo.accountId + " has "
+ foo.totalOrders + " total orders");
}
rawResults.close();
Hope this helps.
This is my db helper class, that creates a db when the app is installed the first time.
When I register a new user, if his name is letters like "john", it gives me an exception.
However, usernames like 4, 56 (i.e.: digits only) give no errors. Why?
class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, "myDB", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.d("x", " database CREATED!!! -------------------------");
db.execSQL("create table userData ("
+ "id integer primary key autoincrement,"
+ "name text,"
+ "password text,"
+ "hero int,"
+ "level int,"
+ "loggedin int"
+ ");");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
EDIT:
This is the piece of code where I actually try to update my db.
public void login(View v){
//..some code here
db.execSQL("update userData set loggedin=1 where name=" + username2) ;
}
All strings in sql must be enclosed by '. Quoted from https://www.sqlite.org/lang_expr.html:
"A string constant is formed by enclosing the string in single quotes ('). A single quote within the string can be encoded by putting two single quotes in a row - as in Pascal. C-style escapes using the backslash character are not supported because they are not standard SQL."
if his name is letters like "john", it gives me an exception.
However, usernames like 4, 56 (i.e.: digits only) give no errors. Why?
Wild Guess: You forgot to enclose John in single quotes, i.e.: 'John'.
The reason for this being that John is a string.
And strings must be delimited by single quotes (')
Be aware that, if the string itself contains a quote (or apostrophe), i.e. 'I'm aware of that', then the apostrophe it has to be doubled, i.e. 'I''m aware of that'.
If you don't want to hassle with quotes, there's a better way to make Android handle it for you: bound parameters.
In practice, all the values in your query should be replaced by a question mark placeholder (?).
And you give the query a String array containing all the values to be replaced.
This way you are also protected against SQL injection.
An example would clarify the concept better:
// Two values to be passed...
final String sql =
"SELECT date, score FROM " + DB_TABLE +
" WHERE strftime('%Y', date) = ? AND " +
"CAST((strftime('%m', date)) AS INTEGER) = ? ORDER BY date DESC";
// ... into the string array parameter of the rawQuery() overload
final Cursor cur =
db.rawQuery
(
sql,
new String[]
{
String.valueOf(CLS_Utils.yearUsing),
String.valueOf(month)
}
);
Note.
The same technique applies to execSQL() as well.
Therefore it can be used on INSERTs, UPDATEs and DELETEs as well.
I'm developing an Android application and i'm using a Sqlite database to store some bitmaps. I want some images to be automatically inserted when the user installs the application.
I'm using the SQLiteOpenHelper class like this:
public class DatabaseHelper extends SQLiteOpenHelper {
...
DatabaseHelper(Context context, String nameOfDB, int version, String[] scriptSQLCreate,
String scriptSQLDelete) {
super(context, nameOfDB, null, version);
this.scriptSQLCreate = scriptSQLCreate;
this.scriptSQLDelete = scriptSQLDelete;
}
#Override
public void onCreate(SQLiteDatabase db) {
int numScripts = scriptSQLCreate.length;
for(int i = 0; i<numScripts; i++){
Log.i(TAG,"Creating database, executing script " + i);
db.execSQL(scriptSQLCreate[i]);
}
}
}
...
I want to pass a constant to the scriptSQLCreate parameter shown above that would be like so:
private static final String[] SCRIPT_DATABASE_CREATE = {
"create table memes( id integer primary key autoincrement," +
+ " img blob not null," +
+ " name text not null unique)" ,
"insert into memes(img,name) values(BITMAP1,'1.jpg')",
"insert into memes(img,name) values(BITMAP2,'2.jpg')",
"insert into memes(img,name) values(BITMAP3,'3.jpg')"}
}
Any help will be much apreciated,
Thx,
Tulio Zahn
If you really, really want to you can use a very long hex literal as a blob literal:
insert into memes(img, name) values(X'0102030405060708090a0b0c0d0e0f', '1.jpg')
However, this is usually a bad idea; instead, go look at parameterised queries. They will let you compile a statement once using placeholders instead of actual values, and then reuse it many times, filling in the placeholders as needed:
SQLiteStatement p = sqlite.compileStatement("insert into memes(img, name) values(?, ?)");
byte[] data = loadData("1.jpg");
p.bindBlob(1, data);
p.bindString(2, "1.jpg");
p.execute();
byte[] data = loadData("2.jpg");
p.bindBlob(1, data);
p.bindString(2, "2.jpg");
p.execute();
(Warning --- code not tested.)
In general you should be using parameterised queries everywhere, as they're a sure-fire way to avoid SQL injection attacks, plus are usually easier and clearer. Assembling SQL queries by glueing strings together should be avoided at all costs.
Your data table has some invisible word which you can not see. Check your db file with the db tools like navicat for sqlite. Please pay attention to the error word in the table.
I have read most of the questions related to this exception but none of them are clear or indicative of why db.insert would throw this error. It was working fine without errors until I manually deleted the db from DDMS. Following is my SQLiteOpenHelper code:
public class LoginSQLiteOpenHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "logincredentials.sqlite";
public static final int DB_VERSION_NUMBER = 1;
public static final String DB_TABLE_NAME = "credentials";
public static final String USERNAME = "user_name";
public static final String PASSWORD = "password";
private static final String DB_CREATE_SCRIPT = "create table " + DB_TABLE_NAME +
"( _id integer primary key autoincrement," +
USERNAME + " text not null, " +
PASSWORD + " text not null );" ;
public LoginSQLiteOpenHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION_NUMBER);
}
#Override
public void onCreate(SQLiteDatabase aSqliteDB) {
Logger.d("Create", "Creating the database...");
aSqliteDB.execSQL(DB_CREATE_SCRIPT);
}
}
My code for inserting the values is:
ContentValues contentValues = new ContentValues();
contentValues.put(LoginSQLiteOpenHelper.USERNAME, loginId);
contentValues.put(LoginSQLiteOpenHelper.PASSWORD, password);
database.insert(LoginSQLiteOpenHelper.DB_TABLE_NAME, null, contentValues);
This is why it occurred to me. If you declare one of your column name type as UNIQUE in your Create Table query in Database and try to insert a non unique variable, it invokes SQLiteConstraintException error.
A UNIQUE constraint is similar to a PRIMARY KEY constraint, except that a single table may have any number of UNIQUE constraints. For each UNIQUE constraint on the table, each row must feature a unique combination of values in the columns identified by the UNIQUE constraint. As with PRIMARY KEY constraints, for the purposes of UNIQUE constraints NULL values are considered distinct from all other values (including other NULLs). If an INSERT or UPDATE statement attempts to modify the table content so that two or more rows feature identical values in a set of columns that are subject to a UNIQUE constraint, it is a constraint violation. Source - http://www.sqlite.org/lang_createtable.html
I have read pretty much all forums looking for an exact reason for the occurrence of this exception. However, nowhere it clearly states so. However, by means of this code of mine, I can explain why it ocurred for me.
The code snippet I provided, is actually flawless. I am doing exactly what is required to do a db.insert().
However, i figured out the exception in 2 steps.
1. first time when i inserted values, I did not insert a value for the column Password.
2. second time, I added a value for column for Password, but due to incorrect passing of values it was null.
hence, I deduced from this exercise, that no column are allowed null values. You must initialize them with some value.
Please feel free to comment/add or correct me if I am wrong. I would like anyone else running into this issue to be clear on it as there are no good documentation on this exception.