I have two tables in which the second table has a foreign key which is defined as table 1's primary key. Under the add operation how can I reference the newly added table 1 key to use as table 2's foreign key?
// Project Table columns names
private static final String KEY_ID = "id"; // Primary, integer
private static final String KEY_NAME = "name"; // Unique, text
// Images Table column names
private static final String KEY_IM_ID = "id"; // Primary, integer
private static final String IM_URI = "uri"; // text
private static final String PROJ_IMAGE_ID = "proImgId"; // foreign for Projects Table
public void addProject(Project project) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values_PT = new ContentValues(); // PROJECTS TABLE
ContentValues values_IT = new ContentValues(); // IMAGES TABLE
values_PT.put(KEY_NAME, project.getName()); // project name
// does the KEY ID get added on its own?
values_IT.put(IM_URI, project.getURI()); // image uri
values_IT.put(PROJ_IMAGE_ID, ????????);
}
PROJ_IMAGE_ID needs to have KEY_ID's value, however I do not know how retrieve it. Is there a way to do this?
If your ID columns are declared as INTEGER PRIMARY KEY, then they are autoincrementing and will get their value automatically if you don't set them when inserting.
To get the ID of a new record, you have to actually insert the record first; the new ID is the return value of the insert() function.
Related
I'm trying to use references to drawable and String resources from a SQLite database to display the appropriate resources in a fragment. I have a database helper file to populate the database, a database utilities file to create a cursor (or just get the cursor data in an array), and the fragment file.
DatabaseHelper.java
DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
private void updateMyDatabase(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 1) {
db.execSQL("CREATE TABLE FOOD (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "NAME TEXT, "
+ "IMAGE_RESOURCE_ID INTEGER, "
+ "QUOTE INTEGER);");
insertFood(db,"Alcohol", R.drawable.alcohol, R.string.symptom9);
}
private static void insertFood(SQLiteDatabase db, String name, int toxicity, int resourceId, int quote){
ContentValues foodValues = new ContentValues();
foodValues.put("NAME", name);
foodValues.put("TOXICITY", toxicity);
foodValues.put("IMAGE_RESOURCE_ID", resourceId);
foodValues.put("QUOTE", quote);
db.insert("FOOD", null, foodValues);
}
}
Here, R.drawable.alcohol = 2131099733
I'm using Android Studio and when I mouse over the values I'm adding to the database and display a drawable using one of those values, it's the correct drawable, but when I request a cursor (or array based on the cursor), the value that the cursor includes is completely different from the value stored in the database and produces a resource not found error.
I tried returning a data array from the helper method, but that also gave incorrect integer references for the drawables and strings so, I'm returning the cursor from the helper method instead:
DatabaseUtilities.java
//get all of the database data for a particular food given that food's name
public static Cursor getFoodById(Context context, long itemId){
try {
SQLiteOpenHelper DatabaseHelper = new DatabaseHelper(context);
SQLiteDatabase db = DatabaseHelper.getReadableDatabase();
return db.query(DatabaseHelper.FOOD,
new String[]{
DatabaseHelper.NAME, DatabaseHelper.IMAGE_RESOURCE_ID,
DatabaseHelper.QUOTE},
"_id = ?", new String[] {Long.toString(itemId)}, null, null, null
);
} catch (SQLiteException e) {
//TODO Add toast - food not available
return null;
}
}
Finally, I'm trying to display the values here:
DetailFragment.java
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Cursor items = DatabaseUtilities.getFoodById(getActivity(), itemId);
if(items.moveToFirst()) {
//set appropriate img
int img = items.getInt(1);
ImageView photo = (ImageView) view.getRootView().findViewById(R.id.detail_photo);
photo.setImageResource(img);
int quote = items.getInt(2);
TextView desc = (TextView) view.getRootView().findViewById(R.id.detail_text);
String descText = getString(quote);
desc.setText(descText);
}
}
This is log output of all of the cursor columns from the last file:
DetailFragment - cursor: Alcohol, 2131165269, 2131558463
The value after Alcohol should be R.drawable.alcohol, 2131099733, but the cursor returns 2131165269 instead. The same is the case with the string reference after the drawable reference. Also, the cursor returns different values for each inserted row, they're just the wrong values and I don't know where they're coming from or if there's a way to convert them to the correct values.
Everything in the program works except that the database doesn't return the correct resource references.
Don't store in the table the integer ids of resources.
Their values are not guaranteed to be the same every time you make changes in the resources and recompile your project.
Instead store the resource ids as string literals.
So change the table's definition to:
CREATE TABLE FOOD (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "NAME TEXT, "
+ "IMAGE_RESOURCE_ID TEXT, "
+ "QUOTE TEXT);
Now store in the columns IMAGE_RESOURCE_ID and QUOTE the string ids.
When you retrieve such a string id from the table by using a cursor, you can get its integer id this way:
int drawableId = getResources().getIdentifier(drawableString, "drawable", getPackageName());
int stringId = getResources().getIdentifier(stringString, "string", getPackageName());
You may need to provide a valid Context to getResources() and getPackageName(), like:
context.getResources().getIdentifier(drawableString, "drawable", context.getPackageName());
Replace drawableString and stringString with the values you retrieved from the table for the image and the string.
If you make the above proposed changes in the definition of the table, you must uninstall the app from the device/emulator and rerun so the database is deleted and recreated with the new definition of the table.
This is my query and associative variables:
public static final String DATABASE_NAME = "HDL_db";
public static final String TABLE_NAME = "HDL_table";
public static final String COL_3 = "Arrival_Time";
public static final int database_version = 1;
public String CREATE_QUERY = "CREATE TABLE " + TABLE_NAME + " (" +
COL_3 + " DATE)";
This is the resultant query format in SQLite Manager (Mozilla Firefox add-on):
CREATE TABLE HDL_table(Arrival TimeDATE)
should be:
CREATE TABLE HDL_table (Arrival_Time DATE) [based on spaces I have added in original query]
and so leaves me with the following table structure in SQLite Manager:
SQLite Manager Table Structure
I want to have the 'Name' column set to 'Arrival_Time' and the 'Type' set to 'DATE' .. because it will be a date that workers arrive on site.
Personally, I think the spaces in the query are the problem, however when I add in the spaces in the original query, export and run the database file through SQLite Manager and check the resultant table structure .. it is in the wrong format.
Any help with this would be great, thanks.
In your column's name must not contain spaces. SQLite does not have a storage class set aside for storing dates and/or times. Instead, the built-in Date And Time Functions of SQLite are capable of storing dates and times as TEXT, REAL, or INTEGER values:
"CREATE TABLE IF NOT EXISTS HDL_table (_id integer primary key, arrival_time text)"
Source: https://www.sqlite.org/datatype3.html
I have the following two tables:
Orders
_id
customer
note
ready
OrderTransactions
_id
orderid(links to orders._id)
product
quantity
What I want to do is delete all OrderTransactions that have an order where ready is equal to "y"
I've seen the join mysql statements to do this, but I don't know how to implement those joins in the mDb.delete statement below
public OrdersDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
private static final String ORDERS_CREATE =
"create table orders (_id integer primary key autoincrement, "
+ "customer text not null, note text not null, export text not null);" ;
private static final String ORDERPRODUCTS_CREATE =
"create table orderproducts (_id integer primary key autoincrement, "
+ "orderid integer not null, product text not null, quantity text not null);";
public boolean deleteOrderProductsAllReady(long orderId) {
return mDb.delete(DATABASE_TABLE_ORDERPRODUCTS, ***criteria***, null) > 0;
}
I think the query should look like this:
DELETE ordtran
FROM OrderProducts AS ordtran
INNER JOIN Orders AS ord
ON ordtran.orderid = ord._id
WHERE [ready="y"]
but I don't know how to put that into the above mDb.delete syntax.
I keep getting this error:
"table keyTable has no column named number"
Still pretty new to Android, so no clue why this happens, can anyone spot the error?
This is my Database class:
public class KeyDatabase extends SQLiteOpenHelper {
private static final String database_name = "KeyDatabase.db";
private static final int database_version = 1;
KeyDatabase (Context context){
super(context,database_name,null,database_version);
}
#Override
public void onCreate (SQLiteDatabase db){
db.execSQL("CREATE TABLE " + KeyTableClass.table_name
+ "(" + KeyTableClass.id + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ KeyTableClass.number + " TEXT, "
+ KeyTableClass.key + " TEXT);");
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
db.execSQL("DROP TABLE IF EXISTS " + KeyTableClass.table_name);
onCreate(db);
}
public long InsertKey (String number, String key){
ContentValues valuesToInsert = new ContentValues();
valuesToInsert.put(KeyTableClass.number, number);
valuesToInsert.put(KeyTableClass.key, key);
SQLiteDatabase sd = getWritableDatabase();
long result = sd.insert(KeyTableClass.table_name, KeyTableClass.number, valuesToInsert);
return result;
}
This is my class for my table:
public class KeyTableClass {
//The name of the table
public static final String table_name = "keyTable";
//The columns of the table
public static String id = "id";
public static String number = "number";
public static String key = "key";
}
Maybe you've edited the DB onCreate but didn't let it re-run?
Try uninstalling/install the App, Or update database_version to =2.
You don't fit the requirements for the insertion :
public long insert (String table, String nullColumnHack, ContentValues values)
Added in API level 1 Convenience method for inserting a row into the
database.
Parameters table the table to insert the row into
nullColumnHack optional; may be null. SQL doesn't allow inserting a
completely empty row without naming at least one column name. If your
provided values is empty, no column names are known and an empty row
can't be inserted. If not set to null, the nullColumnHack parameter
provides the name of nullable column name to explicitly insert a NULL
into in the case where your values is empty. values this map contains
the initial column values for the row. The keys should be the column
names and the values the column values Returns the row ID of the newly
inserted row, or -1 if an error occurred
Could you try to do :
sb.insert(table_name, null, valuesToInsert);
From an Android SQLite database point of view - I have a table which has a field with BLOB type and then I want to query this table contents based on this BLOB field.
I can insert my BLOB field using ContentValues and retrieve it using:
cursor.getBlob(0)// index
I just can't figure out how to query this table contents based on this BLOB field and have found nothing about this problem.
You can't query the (textual? binary? other?) contents of a blob.
If you look, you'll see the contents is in hex:
EXAMPLE: X'53514C697465'.
Suggestions:
Create a new text column, e.g. "blob_index". You can search on the "index" column, then fetch the blob.
Alternatively, just store the data as "text".
I found that you can query on a blob. One needs to use the hex() function on the query.
For example I'm using UUIDs in my database rows as a unique key that I can generate locally and still be sure of uniqueness on the server.
CREATE TABLE example (_ID INTEGER PRIMARY KEY AUTOINCREMENT,
uuid BLOB NON NULL UNIQUE,
...)
When inserting data the following works:
final ContentValues values = new ContentValues(4);
values.put(Contract.Line.COL_UUID,
UuidFactory.toBlob(uuid));
Given a query URI in the form:
content://package.example.com/example/uuid/11112222-3333-0444-0555-666677778888
the query becomes:
final SQLiteDatabase db = mHelper.getReadableDatabase();
return db.query(table, projection,
"hex(uuid) = ?",
new String[] { UuidFactory.toHex(uri.getLastPathSegment()) },
null, null, null, null);
In UuidFactory (which also contains the code to generate new UUIDs) the follow static functions are defined thus:
#NonNull
public static String toHex(#NonNull final UUID uuid) {
return String.format("%016X%016X",
uuid.getMostSignificantBits(),
uuid.getLeastSignificantBits());
}
#NonNull
public static String toHex(#NonNull final String uuid) {
return toHex(UUID.fromString(uuid));
}
#NonNull
public static byte[] toBlob(#NonNull final UUID uuid) {
final ByteBuffer buf = ByteBuffer.allocate(16);
buf.putLong(uuid.getMostSignificantBits());
buf.putLong(uuid.getLeastSignificantBits());
return buf.array();
}
And for completeness:
#NonNull
public static UUID fromBlob(#NonNull final byte[] array) {
final ByteBuffer buf = ByteBuffer.allocate(16);
buf.mark();
buf.put(array);
buf.reset();
final long msb = buf.getLong();
final long lsb = buf.getLong();
return new UUID(msb, lsb);
}