inserting null as Integer value into a database - android

I am trying to store a null value into the database but everytime I load the value I get 0.
I declare the field just like "intVal integer"
This is how I retrieve it:
Integer x;
x = cursor.getInt(cursor.getColumnIndexOrThrow(MyDBAdapter.KEY_X));
Is that reliable? or is it undefined?
So it seems to me one cannot save null as an undefined integervalue
Many thanks

From the getInt() documentation:
Returns the value of the requested column as an int.
The result and whether this method throws an exception when the column value is null, the column type is not an integral type, or the integer value is outside the range [Integer.MIN_VALUE, Integer.MAX_VALUE] is implementation-defined.
So, it's an implementation detail which you shouldn't rely on.
You can still get the effect you want, though: you simply do the null check before you read the value.
int index = cursor.getColumnIndexOrThrow(MyDBAdapter.KEY_X);
Integer x = null;
if (!cursor.isNull(index)
x = cursor.getInt(index);
// now x is either null or contains a valid value

SQLite is dynamically typed. Since you defined column of type Integer and it didn't find a value it returned 0 based on the hint.
Try using String as the type of column

As Rajdeep Dua mentioned, SQLite uses a dynamic typing. Here's what the documentation says:
Most SQL database engines (every SQL database engine other than
SQLite, as far as we know) uses static, rigid typing. With static
typing, the datatype of a value is determined by its container - the
particular column in which the value is stored.
SQLite uses a more general dynamic type system. In SQLite, the
datatype of a value is associated with the value itself, not with its
container.
The Android documentation says that the result of getInt() when the column value is null is implementation defined. For me, it returns 0 as well.
So I used getString() instead, although the result of this method is also implementation defined, for me, it returns null when the column value is null, or a string containing the number otherwise.
So the code looks like this:
Strint strVal = cursor.getInt(cursor.getColumnIndexOrThrow(MyDBAdapter.KEY_X));
if(strVal != null){
int intVal = Integer.parseInt(strVal);
}

Related

Greater than operator (>) not giving correct result from database

I've text type column named 'amountDesc' having some values in it. I want to get all values which have values greater than 100. I wrote a query but it's not giving the correct result.
Database as you can see as under.
i've tried this code:
String query = "SELECT amountDesc FROM increment WHERE amountDesc > 100";
Cursor rawQuery = getReadableDatabase().rawQuery(query, null);
if (rawQuery.moveToFirst()) {
while (!rawQuery.isAfterLast()) {
String value = rawQuery.getString(rawQuery.getColumnIndex("amountDesc"));
rawQuery.moveToNext();
Log.d("tvlateamoutn1", value);
}
}
and getting these values on Logcat:
500 50 200 50
as you can see its not correct values as I required > 100 values. I know its question of for most beginners level but I stuck in it. Kindly resolve.
I've text type column named 'amountDesc' having some values in it.
So in your table definition you have amountDesc TEXT or something equivalent?
From the documentation:
A column with TEXT affinity stores all data using storage classes NULL, TEXT or BLOB. If numerical data is inserted into a column with TEXT affinity it is converted into text form before being stored.
and:
If one operand has TEXT affinity and the other has no affinity, then TEXT affinity is applied to the other operand.
Since the column has text affinity, the other operand is being converted from the integer 100 to the string '100'. The string '50' is greater than the string '100' because '5' is greater than '1'. Thus, your query is returning exactly what you're asking it to return. You're just asking it something different from what you think you are.
If you want to treat the values in that column as integers and compare them accordingly, use INTEGER not TEXT when creating the table. A poor workaround for not picking the correct affinity for the data stored in the column is to cast the values to the appropriate type when using them in calculations... CAST(amountDesc AS INTEGER) > 100 or something like that.
(Reading and understanding the linked documentation on datatypes and affinity is essential for using sqlite effectively.)
Can you check data type of amountDesc in schema. If declared data type is string, you can not compare with integer (100).

Can you set default value of a column based on the calculations of previous two columns in SQLite?

I have a table in SQLite where I would like to set the value of 3rd column based on the input value of first two columns.
Does SQLite even support an expression in the default value of a column?
create table contract(
id primary key autoincrement,
insurance_pct integer not null default 0,
historical_yield integer not null default 0,
guaranteed_yield integer not null default (insurance_pct/100 * historical_yield)
)
When I run the above statement I see following error.
Query execution failed
Reason:
SQL Error [1]: [SQLITE_ERROR] SQL error or missing database (default value of column [GUARANTEED_YIELD] is not constant)
As the error message "default value of column [GUARANTEED_YIELD] is not constant" clearly points out, you cannot use variables in the default expression.
One way to achieve what you want is to make an after insert trigger, that updates the column, when it was inserted as null. That however requires, that the column is not declared not null as otherwise the INSERT will fail. So you'd have to check that too in a before update trigger.
CREATE TABLE contract
(id integer PRIMARY KEY
AUTOINCREMENT,
insurance_pct integer
NOT NULL
DEFAULT 0,
historical_yield integer
NOT NULL
DEFAULT 0,
guaranteed_yield integer
NULL
DEFAULT NULL);
CREATE TRIGGER contract_ai
AFTER INSERT
ON contract
FOR EACH ROW
WHEN (new.guaranteed_yield IS NULL)
BEGIN
UPDATE contract
SET guaranteed_yield = insurance_pct / 100 * historical_yield
WHERE id = new.id;
END;
CREATE TRIGGER contract_bu
BEFORE UPDATE
ON contract
FOR EACH ROW
WHEN (new.guaranteed_yield IS NULL)
BEGIN
SELECT raise(FAIL, 'NOT NULL constraint failed: contract.guaranteed_yield');
END;
One other thing I noticed: guaranteed_yield is an integer but your default expression pretty likely produces non integer values. You might lose something due to the required rounding. I'm not sure whether this is intentional.
Addendum:
Looking at the comments to your question I'm not sure whether you merely want a default -- i.e. the value of guaranteed_yield should have the value of the expression, if no other value is explicitly given at INSERT but it is possible for it to have other (non null) values either from an INSERT or or a subsequent UPDATE -- or if you intend this to be a calculated column, that always has the value the expression gives. In the latter case: I second the other commenters. This is a potentially dangerous thing regarding inconsistencies. Preferably use the expression in your queries or create a view.
This is not supported in SQLite.
The CREATE TABLE documentation states :
An explicit DEFAULT clause may specify that the default value is NULL, a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.
Further, the document defines the concept of constant expression :
For the purposes of the DEFAULT clause, an expression is considered constant if it contains no sub-queries, column or table references, bound parameters, or string literals enclosed in double-quotes instead of single-quotes.
This namely excludes references to other columns.
Other possible approaches in your use case :
compute the value dynamically in your DML queries (UPDATE and INSERT)
use a trigger to provide a dynamic default on DML operations

What happens when declaring a column NOT NULL in SQLite db in android

When you define a column in an android SQLite database, what happens when you say define a field as TEXT NOT NULL. I know that it may not be null, but lets say you insert a value to only one column or field, does the rest of the columns default to an empty string "" if they are declared TEXT NOT NULL ?
You'll have to supply a value for each of the NOT NULL columns.
OR provide a default value: ..., myField TEXT NOT NULL DEFAULT '', ...
For reference: http://www.tutorialspoint.com/sqlite/sqlite_constraints.htm
If you did not specify default values for those columns it will just thrown an Exception. NULL in SQLite represents absense of value, therefore it's not equal to an empty string.

Binding NULL arguments with queryWithFactory

I'm writing an Android app that needs to write to the SQLite database. Currently it's using rawQueryWithString to build the update query, and I'm using ? placeholders in my query combined with the selectionArgs argument to pass in the actual values.
However, sometimes I actually want to update my column (of type Date) to NULL, but if I pass in null in my selectionArgs then I get this error:
IllegalArgumentException: the bind value at index 1 is null
I can't really see how I'm supposed to make it work when the value is actually null. I guess I could pass in an empty string, which in the case of a Date column like this might just work, but suppose it was a string column and I actually did want to mean NULL in contrast to the empty string (or are they considered equivalent in SQLite?)
Here's the code:
String timestampStr = null; // Obviously not really set like this
SQLiteDatabase d = getWritableDatabase();
DBCursor c = (DBCursor) d.rawQueryWithFactory(
new DBCursor.Factory(),
"Update subject set schedulingTimestamp = ? where identifier = ?",
new String[] { timestampStr, subjId.toString() },
null);
d.close();
The column was added with the following query, so I presume it's a nullable column since I didn't specify otherwise:
ALTER TABLE subject ADD schedulingTimestamp DATE;
Wildcards are not meant to be used for inserting/updating values in SQL, AFAIK. In Android, you can use ContentValues instead in conjunction with the update() method, instead of trying to shoehorn it in the raw query method.

How to handle nullable integer columns in SQLite database

I have an Android SQLite table definition like this:
create table MyTable(..., myDate integer, ...);
Later in my code I query this table to retrieve the value for myDate via a cursor:
long dateInstant = cursor.getLong(cursor.getColumnIndexOrThrow("myDate"));
However, I'm wondering if this is the best approach. If the value is not set (i.e. null on the database) the above method returns 0, which happens to also be a valid value. I need to differentiate valid values from null values. Also, from the javadoc for getLong:
The result and whether this method throws an exception when the column value is null, the column type is not an integral type, or the integer value is outside the range [Long.MIN_VALUE, Long.MAX_VALUE] is implementation-defined.
which seems to suggest, if I read this correctly, that at some point in the future the SQLite implementation shipped in Android may choose to throw an exception rather than return 0. I'm looking for a consistent solution across Android versions.
In short, how can I robustly handle the retrieval of integer data from a column in a way which allows me to differentiate between valid values and null?
You can do
long dateInstant = 0; // some value to represent null
if (!cursor.isNull (colIndex))
dateInstance = cursor.getLong (colIndex);

Categories

Resources