sqlite number format exception not working [duplicate] - android

This question already has answers here:
SQLITE date no type checked
(2 answers)
Closed 8 years ago.
I am using a sqlite database in my android application. In my Employee table there are three fields "emp_id","ph no","address" with data type integer, integer and text. emp_id is the primary key. If I entered string for "emp_id" and try to insert into table then it gives number format exception wich is correct but for "ph no". If I enter the string value then it is not throwing an exception, it's accepting it.
Here is my piece of code:
}else{
sqlcon.open();
try {
sqlcon.insert(DisaplayTables_list.getTableNameFromListView, storeEditextText);
} catch (NumberFormatException e) {
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_LONG).show();
//Toast.makeText(getApplicationContext(),"column value already exists",Toast.LENGTH_LONG).show();
}
System.out.println("size of storeEdittext=" + storeEditextText.size());
System.out.println("size of Edit Texts: " + allEds.size());
}
Intent i = new Intent(getApplicationContext(), DisplayTable_Grid.class);
startActivity(i);
sqlcon.close();
}

SQLite lets me insert a string into a database column of type integer!
This is a feature, not a bug. SQLite uses dynamic typing. It does not enforce data type constraints. Data of any type can (usually) be inserted into any column. You can put arbitrary length strings into integer columns, floating point numbers in boolean columns, or dates in character columns. The datatype you assign to a column in the CREATE TABLE command does not restrict what data can be put into that column. Every column is able to hold an arbitrary length string. (There is one exception: Columns of type INTEGER PRIMARY KEY may only hold a 64-bit signed integer. An error will result if you try to put anything other than an integer into an INTEGER PRIMARY KEY column.)
But SQLite does use the declared type of a column as a hint that you prefer values in that format. So, for example, if a column is of type INTEGER and you try to insert a string into that column, SQLite will attempt to convert the string into an integer. If it can, it inserts the integer instead. If not, it inserts the string. This feature is called type affinity.
Click here for refference
hope it clear all your doubts happy coding :)

This is a feature, not a bug. SQLite uses dynamic typing. It does not enforce data type constraints. Data of any type can (usually) be inserted into any column. You can put arbitrary length strings into integer columns, floating point numbers in boolean columns, or dates in character columns. The datatype you assign to a column in the CREATE TABLE command does not restrict what data can be put into that column. Every column is able to hold an arbitrary length string. (There is one exception: Columns of type INTEGER PRIMARY KEY may only hold a 64-bit signed integer. An error will result if you try to put anything other than an integer into an INTEGER PRIMARY KEY column.)
But SQLite does use the declared type of a column as a hint that you prefer values in that format. So, for example, if a column is of type INTEGER and you try to insert a string into that column, SQLite will attempt to convert the string into an integer. If it can, it inserts the integer instead. If not, it inserts the string. This feature is called type affinity.

Related

What is meant by saying that String is a numeric type in android SQlite? [duplicate]

This question already has answers here:
Difference Between "Text" and "String" datatype in SQLite
(2 answers)
Closed 2 years ago.
I specified columns datatype as String while creating database in my android project.I encountered the below lines as suggestions.What does that mean?
Using column type STRING; did you mean to use TEXT? (STRING is a numeric type and its value can be adjusted; for example, strings that look like integers can drop leading zeroes.
Don't use the data type String because there is no such data type in SQLite.
Actually SQLite does not use data types but 5 storage classes for each value stored (not for each column):
NULL, INTEGER, REAL, TEXT and BLOB
Also SQLite assigns 1 of 5 type affinities to each column:
TEXT, NUMERIC, INTEGER, REAL, BLOB
and you should use any of these affinities when you define the data type of a column.
For your case the type affinity determined for a column defined as String, according to these rules:
If the declared type contains the string "INT" then it is assigned INTEGER affinity.
If the declared type of the column contains any of the strings "CHAR", "CLOB", or "TEXT" then that column has TEXT affinity. Notice that the type VARCHAR contains the string "CHAR" and is thus assigned TEXT affinity.
If the declared type for a column contains the string "BLOB" or if no type is specified then the column has affinity BLOB.
If the declared type for a column contains any of the strings "REAL", "FLOA", or "DOUB" then the column has REAL affinity.
Otherwise, the affinity is NUMERIC.
will be NUMERIC because none of the first 4 rules can be applied.
So change it to TEXT which is the suitable affinity.
You can find all about data types in SQLite here: Datatypes In SQLite Version 3

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).

How to insert Long Type value to SQLite

I have a value from the epoch time like this 1549251913000, I save this value to SQLite. I create the table like the following:
CREATE TABLE TABLE_BOOKMARK (COLUMN_ID INTEGER PRIMARY KEY AUTOINCREMENT, COLUMN_TITLE TEXT, COLUMN_SOURCE TEXT, COLUMN_DATEANDTIME INTEGER, COLUMN_GUID TEXT);
that value is COLUMN_DATEANDTIME but with INTEGER type. but when I take the value, it doesn't match what I expected. it becomes like this -1231280856.
Please give me some advice, thanks
I have tried this solution but still mismatch when I get it from SQLite (seems it didn't work with my problem)
Create a column in as INTEGER datatype put LONG value into INTEGER in column
Make sure when you retrieve the value from cursor as LONG
Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_NAME, null);
long value = cursor.getLong(0);
For more : SQLite DataType Doc
Just to clarify the column type is, with one exception, largely irrelevant as any type of data can be stored in any type of column.
The exception is the rowid column or an alias of the rowid column, such a column MUST store an integer. By integer it is a 64bit signed integer and thus encompasses a java long.
The column type itself is also flexible for example CREATE TABLE mytable (mycolumn a_pretty_weird_column_type) is valid (as would be LONG). Such types are converted according to 5 rules to the column affinity.
Putting the above together, using :-
CREATE TABLE IF NOT EXISTS mytable (mycolumn a_pretty_weird_column_type);
DELETE FROM mytable;
INSERT INTO mytable VALUES
(1549251913000),
(999999999999999),('Fred'),(x'010203040506070809'),(0.234567),(null),
('999999999999999'), -- Note although specified as TEXT as mycolumn is effectively NUMERIC stored as INTEGER
('0.234567') -- As above but stored as REAL
;
SELECT
*,
typeof(mycolumn) AS coltype, -- The column type (note as per value not column definition)
hex(mycolumn) AS as_hex, -- Convert column to a hex representation of the data
CAST(mycolumn AS TEXT) AS as_text, -- follow rules
CAST(mycolumn AS INTEGER) AS as_integer,
CAST(mycolumn AS REAL) AS as_real,
CAST(mycolumn AS NUMERIC) AS as_numeric,
CAST(mycolumn AS BLOB) AS as_blob
FROM mytable;
results in :-
The bible as such is Datatypes In SQLite Version 3.
but when I take the value, it doesn't match what I expected. it
becomes like this -1231280856
The Issue
As such your issue is nothing to do with the column type, not SQLite as such, rather it's due to using the Cursor getInt method, instead of the getLong method.
One answer says,
Its always better to store date and time in form of Text in sqlite.
This is incorrect, from a space point of view and therefore the underlying efficiency the use of a numeric representation, i.e. 64bit signed integer as per SQL As Understood By SQLite - Date And Time Functions - Time Strings (maximum of 8 bytes), of the date and time will be more efficient than storing the 19 bytes (for an accuracy down to a second).
As per the docs sqlite does not have default storage class for date and time. Its always better to store date and time in form of Text in sqlite. You can then parse them into Date runtime whenever you want to use them

Does value get converted when inserted into database?

I was curious if androids SQLiteDatabase insert method automatically handles type conversion.
Here is my example:
I have a csv file with a column name of age. Its type will be an INTEGER.
Lets say I have already created the database and table.
Now I am parsing the csv file with CSVReader, which parses each line and inserts each value into an index of a String[].
In order to insert each line of data into the database, I have to use a ContentValue object, which allows me to store values in it.
//Parse each line and store in line...
ContentValue values = new ContentValue();
values.put(KEY_AGE, line[1]); // Assume line[1] is the age
database.insert(table, null, values);
If I store the age value as a string (as seen above), and then insert it into the table, does Android handle the conversion to INTEGER before inserting it into the database?
I am asking this because I am trying to insert a bunch of tables into a database, and it looks much cleaner when I can just iterate through an array then explicitly state each put call, i.e:
Also if anyone has any design suggestions feel free to tell me.
CLEAN
int i = 0;
for(String s : TransitContract.Routes.COLUMN_ARRAY) {
values.put(s, line[i]);
i++;
}
UGLY
values.put(TransitContract.Routes.KEY_ROUTE_ID, line[0]);
values.put(TransitContract.Routes.KEY_AGENCY_ID, line[1]);
values.put(TransitContract.Routes.KEY_SHORT_NAME, line[2]);
values.put(TransitContract.Routes.KEY_LONG_NAME, line[3]);
values.put(TransitContract.Routes.KEY_DESCRIPTION, line[4]);
values.put(TransitContract.Routes.KEY_ROUTE_TYPE, Integer.parseInt(line[5]));
values.put(TransitContract.Routes.KEY_URL, line[6]);
values.put(TransitContract.Routes.KEY_COLOR, line[7]);
values.put(TransitContract.Routes.KEY_TEXT_COLOR, line[8]);
return mDatabase.insert(TransitContract.Routes.TABLE_NAME, null, values);
When you declare a column as INTEGER, SQLite will automatically convert strings to numbers, if possible.
See the documentation for Type Affinity.
If your ContentProvider doesn't restrict it (i.e. pass it directly to the SQLiteDatabase.insert() method), it should work. SQLite is not that picky about the types used in queries/inserts and the actual column type.
However, it would be best practice to parse and check the values before inserting. Otherwise you might actually insert a string which can't be parsed as integer and therefore retrieving the value might fail.
References:
Boolean datatype accepting string value and integer value
SQLite table with integer column stores string

Determine data type of a column in SQLite

I'm working on an Android App where the user has different options for sorting the displayed data that comes from the database. Currently my orderBy string that I pass to Androids query() method looks like this:
"LOWER("+columnName+") ASC"
The problem with this is that if the data type in the column specified by columnName is integer, calling LOWER() on it will cause it to be sorted alphabetically, i.e. based only on the leftmost digit, which of course doesn't make any sense for numeric data. Hence I only want to apply LOWER() if the data type of the column is not integer. What I have in mind is a statement like this:
"CASE WHEN [data type of columnName is integer] THEN "+columnName+" ASC ELSE LOWER("+columName+") ASC END"
The part in the brackets is what I don't know how to do. Does SQLite provide a function to determine a column's data type?
Do you really want the type of the column, or the type of the value? (SQLite is dynamically-typed, so the distinction is important.)
If you want the latter, you can use typeof(columnName).
Use:
PRAGMA table_info(table-name);
to get table info.
Taken directly from SQLite docs about datatypes for SQLite Version 3:
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 dynamic type system of SQLite is backwards compatible with the more common static type systems of other database engines in the sense that SQL statements that work on statically typed databases should work the same way in SQLite. However, the dynamic typing in SQLite allows it to do things which are not possible in traditional rigidly typed databases.
Column affinity: use PRAGMA table_info(table-name);. PRAGMA table_info() gives a table with columns cid, name, type, notnull, dflt_value, and pk.
Columns in the result set include the column name, data type, whether or not the column can be NULL, and the default value for the column. The "pk" column in the result set is zero for columns that are not part of the primary key, and is the index of the column in the primary key for columns that are part of the primary key.
Datatype of value: Use typeof(column) to see how values are actually stored by SQLite.
Example adapted from section 3.4:
CREATE TABLE t1(
t TEXT, -- text affinity by rule 2
nu NUMERIC, -- numeric affinity by rule 5
i INTEGER, -- integer affinity by rule 1
r REAL, -- real affinity by rule 4
no BLOB -- no affinity by rule 3
);
-- Values stored as TEXT, INTEGER, INTEGER, REAL, TEXT.
INSERT INTO t1 VALUES('500.0', '500.0', '500.0', '500.0', '500.0');
-- Values stored as TEXT, INTEGER, INTEGER, REAL, REAL.
INSERT INTO t1 VALUES(500.0, 500.0, 500.0, 500.0, 500.0);
-- Values stored as TEXT, INTEGER, INTEGER, REAL, INTEGER.
INSERT INTO t1 VALUES(500, 500, 500, 500, 500);
-- BLOBs are always stored as BLOBs regardless of column affinity.
INSERT INTO t1 VALUES(x'0500', x'0500', x'0500', x'0500', x'0500');
-- NULLs are also unaffected by affinity
INSERT INTO t1 VALUES(NULL,NULL,NULL,NULL,NULL);
Output of PRAGMA table_info(t1);:
0|t|TEXT|0||0
1|nu|NUMERIC|0||0
2|i|INTEGER|0||0
3|r|REAL|0||0
4|no|BLOB|0||0
Output of SELECT typeof(t), typeof(nu), typeof(i), typeof(r), typeof(no) FROM t1; (notice each value in a column has its own datatype):
text|integer|integer|real|text
text|integer|integer|real|real
text|integer|integer|real|integer
blob|blob|blob|blob|blob
null|null|null|null|null
Did you declare the column as an integer when setting up the table? Otherwise sqlite will store it as text and the sorts will act as you've described.
create table if not exists exampletable (columnName integer);
To get information of Table use
PRAGMA table_info(table-name);
If you want the latter, you can use
typeof(columnName)

Categories

Resources