Error inserting values in a table - android

I am reading values from a csv file and I am able to do that accurately. However, when I try to write those values in a systems db's table, I get an error saying one column doesn't exist in the table.
Logcat error:
E/SQLiteLog(318): (1) table hospital has no column named zip
E/SQLiteDatabase(318): Error inserting zip=36301 avgCharges=20313 avgPayment=4895 _id=10001 address=1108 ROSS CLARK CIRCLE providerName=SOUTHEAST ALABAMA MEDICAL CENTER state=AL procedure=057 - DEGENERATIVE NERVOUS SYSTEM DISORDERS W/O MCC discharges=38 city=DOTHAN
E/SQLiteDatabase(318): android.database.sqlite.SQLiteException: table hospital has no column named zip (code 1): , while compiling: INSERT INTO hospital(zip,avgCharges,avgPayment,_id,address,providerName,state,procedure,discharges,city) VALUES (?,?,?,?,?,?,?,?,?,?)
E/SQLiteDatabase(318): at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
Create Table query: (all fields are in TEXT for testing)
query = "CREATE TABLE hospital(_id TEXT PRIMARY KEY, procedure TEXT, providerName TEXT, address TEXT, city TEXT, state TEXT, zip TEXT, discharges TEXT, avgCharges TEXT, avgPayment TEXT)";
db.execSQL(query);
I am sure there is no column type mismatch. It says it cannot find the column named ZIP. i do not understand whats happening here.
Query to insert values:
values.put("_id", hospital.get_id());
values.put("procedure", hospital.get_procedure());
values.put("providerName", hospital.get_providerName());
values.put("address", hospital.get_address());
values.put("city", hospital.get_city());
values.put("state", hospital.get_state());
values.put("zip", hospital.get_zip());
values.put("discharges", hospital.get_discharges());
values.put("avgCharges", hospital.get_avgCharges());
values.put("avgPayment", hospital.get_avgPayment());
db.insert(TABLE_NAME, null, values);
Any ideas on what could be done here? Thanks in advance!

The table needs to be dropped before adding a new column in the code.
You should clear the app data. Else uninstall the app and run it from Studio.

You need to implement the onUpgrade method to drop and add tables whenever the schema is changed. You can look at https://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#onUpgrade(android.database.sqlite.SQLiteDatabase,%20int,%20int).

Related

Unable to insert 'NULL' as text in SQLIte

I am trying to insert text 'NULL' in SQLite table and getting syntax error near :'NULL'.
Below is my SQL insert statement.
db.execSQL("INSERT INTO POINTS_TABLE VALUES('NULL','NULL','NULL')");
I think you need to change your code from
db.execSQL("INSERT INTO POINTS_TABLE VALUES('NULL','NULL','NULL')");
to
db.execSQL("INSERT INTO POINTS_TABLE (COL1,COL2,Col3) VALUES ('NULL','NULL','NULL');");
further to this I think you want to loose the quotation marks unless you want to store the string "NULL" in these columns. if your data types for these columns are not strings then this will throw an error.

How to create a new row in a SQLite table with the ID column only?

I have a table in an SQLite database on Android that only contains a column with the row ID. This table is used to link datasets in different tables. When I try to insert a new row in the table it throws this exception:
android.database.sqlite.SQLiteException: near "null": syntax error
(code 1): , while compiling: INSERT INTO journeyDetailsTable(null)
VALUES (NULL)
My table is created like this:
private static final String CREATE_TABLE_JOURNEY_DETAIL = "create table " +
TABLE_NAME + " (" + ID_COLUMN + " integer primary key autoincrement);";
And I am trying to insert a new row like this:
parentID = db.insert(ANOTHER_TABLE, null, new ContentValues());
Any ideas?
The docs for SQLiteDatabase.insert(String, String, ContentValues) clearly state that SQL doesn't allow inserting a completely empty row without naming at least one column name. This means that if you do not specify any values, you need to specify a column name in which to insert the NULL into. You should be fine with db.insert(ANOTHER_TABLE, ID_COLUMN, new ContentValues()) to accomplish that.
Regardless, you should probably re-think your database structure as having tables set up like this does not seem effective, maintainable and overseeable, especially in the long run.
Just pass ID_COLUMN as column name in your insert, null isn't a column, but passing null to id will let ID be auto-incremented:
INSERT INTO journeyDetailsTable(ID_COLUMN) VALUES (NULL)
demo

How do I get "insert or update" behaviour without using CONFLICT_REPLACE?

My Android app is using an SQLite FTS3 table to provide full text search. I'm using insertWithOnConflict with CONFLICT_REPLACE to update my database, inserting a new row if need be or updating an existing row if it's present.
I was very surprised to find that my table ended up containing duplicate rows — but it looks like this is a documented "feature" of SQLite's FTS modules:
From the SQLite FTS3 and FTS4 Extensions page:
Datatypes and column constraints are specified along with each column.
These are completely ignored by FTS and SQLite.
It's pretty easy to replicate the duplication from the command line:
sqlite> CREATE VIRTUAL TABLE test_duplicates USING FTS3
...> (id INTEGER PRIMARY KEY, name TEXT);
sqlite> INSERT INTO test_duplicates (id, name) VALUES (1, "George");
sqlite> INSERT INTO test_duplicates (id, name) VALUES (1, "George");
sqlite> INSERT OR REPLACE INTO test_duplicates (id, name) VALUES (1, "George");
sqlite> SELECT * FROM test_duplicates;
1|George
1|George
1|George
sqlite>
My question is: what's the best (simplest, most robust) way to replicate the behaviour of CONFLICT_REPLACE?
My ideas at the moment are either to (A) do a SELECT, then an UPDATE or INSERT based on the result or (B) blindly try DELETE the existing row (which may or may not be present) and then INSERT.
refering to the fts document, i found this paragraph:
... each FTS table has a "rowid" column. The rowid of an FTS table behaves in the same way as the rowid column of an ordinary SQLite table, except that the values stored in the rowid column of an FTS table remain unchanged if the database is rebuilt using the VACUUM command. For FTS tables, "docid" is allowed as an alias along with the usual "rowid", "oid" and "oid" identifiers. Attempting to insert or update a row with a docid value that already exists in the table is an error, just as it would be with an ordinary SQLite table.
which means you could use the built-in docid column as your primary key and let the fts table apply it's constraint on it.
I have the same problem. I found out that when we CREATE VIRTUAL TABLE test_duplicates USING FTS3 it will create a column named rowid and it's primary key of this table so that we just need using rowid instead id that will work correctly.
If you change:
INSERT INTO test_duplicates (id, name) VALUES (1, "George");
to:
INSERT INTO test_duplicates (rowid, id, name) VALUES (1, 1, "George");
INSERT INTO test_duplicates (rowid, id, name) VALUES (2, 2, "George");
i won't take credit for this. but i can't find the original link i got this from.
you do a query, then:
if (cursor.moveToFirst()) {
// record exists
} else {
// record not found
I use the following query for INSERT OR REPLACE
INSERT OR REPLACE INTO test_duplicates (`rowid`, `name`) VALUES
((SELECT `rowid` FROM test_duplicates WHERE `name` = "George" LIMIT 1), "George")
And it works. But in this case, you can't supply the rowid. rowid will be handled by Database itself.

SQLite prevents duplicate column names in my VIEW

I am creating a SQLite VIEW that is the result of multiple joined tables. All my tables have an _id column as required by Android. The result has multiple columns with the same _id name, but SQLite adds ":1" and ":2" to the duplicate names so they are no longer duplicates.
If you run the below SQL you can see the resulting view has interesting column names:
CREATE TABLE things ("_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "name" TEXT NOT NULL);
CREATE TABLE thing_colors ("_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "thing_id" INTEGER NOT NULL , "color" TEXT NOT NULL);
INSERT INTO things VALUES ("1","car");
INSERT INTO things VALUES ("2","horse");
INSERT INTO things VALUES ("3","lamp");
INSERT INTO thing_colors VALUES ("1","1","blue");
INSERT INTO thing_colors VALUES ("2","1","red");
INSERT INTO thing_colors VALUES ("3","2","brown");
INSERT INTO thing_colors VALUES ("4","3","silver");
INSERT INTO thing_colors VALUES ("5","3","gold");
CREATE VIEW things_and_colors AS SELECT * FROM things JOIN thing_colors ON things._id=thing_colors.thing_id;
SELECT * FROM things_and_colors;
I find these renamed column names useful but is this normal SQL behavior and is it fine for me to rely on it?
But of course this is just an example, in real life I am joining three tables and the result has about 70 columns in it, of which 3 are named _id.
Don't select star, select the columns individually and assign an alias as needed.
No, you can't depend on the view renaming your columns to avoid conflicts. I don't have a copy of the standard handy so I can't quote chapter and verse but I know that PostgreSQL will say this:
ERROR: column "_id" specified more than once
and MySQL will say this:
ERROR 1060 (42S21): Duplicate column name '_id'
Those are the only databases I have handy at the moment.

Automatically Create Insert Statements to Fill Junction Table in a Pre-Created DB

For a simple android app I'm creating as a teaching tool for myself (for using relational dbs/SQL among other things - pardon the simplicity of the question if you will). I'm pre-creating a sqlite db to ship with the application. I'm doing this based on the following SO question.
I've got two tables with a many to many relationship and a junction table to define those relationships as follows:
CREATE TABLE Names (_id INTEGER PRIMARY KEY,
name TEXT
);
CREATE TABLE Categories (_id INTEGER PRIMARY KEY,
category TEXT
);
CREATE TABLE Name_Category (name_id INTEGER,
category_id INTEGER,
PRIMARY KEY (name_id, category_id),
foreign key (name_id) references Names(_id),
foreign key (category_id) references Categories(_id)
);
I've got sets of insert statements to fill the Names and Categories tables. I'm now faced with the task of filling the junction table. I'm sure that I could create the insert statements by hand by looking up the ids of the names and categories that I want to match, but that seems a bit silly.
In order to automatically create the insert statements for the junction table, I imagine that I could create a script based on a set of name and category pairs that will search for the appropriate ids and dump an insert statement. (I came up with this as I was asking the question and will research it. Don't you love it when that happens?)
Does anybody have any suggestions for ways to do this?
EDIT I added the foreign keys because, as pointed out below, they'll help maintain integrity between the tables.
EDIT #2 To solve this, I created a simple Perl script that would take a text file with name - category pairs and dump them out into another file with the appropriate SQL statements.
The name - category text file has a format as follows:
'Name' 'Category'
The Perl script looks like this:
use strict;
use warnings;
open (my $name_category_pair_file, "<", "name_category.txt") or die "Can't open name_category.txt: $!";
open (my $output_sql_file, ">", "load_name_category_junction_table.sqlite") or die "Can't open load_name_category_junction_table.sqlite: $!";
while (<$name_category_pair_file>) {
if (/('[a-zA-Z ]*') ('[a-zA-Z ]*')/) {
my $sql_statement = "INSERT INTO Name_Category VALUES (
(SELECT _id FROM Names WHERE name = $1),
(SELECT _id FROM Categories WHERE category = $2))\;\n\n";
print $output_sql_file $sql_statement;
}
}
close $name_category_pair_file or die "$name_category_pair_file: $!";
close $output_sql_file or die "$output_sql_file: $!";
You can use this insert in your script or code (replacing the strings or using ?):
insert into Name_Category values(
(select _id from Categories where category='CAT1'),
(select _id from Names where name='NAME1'));
Also, you can alter the Name_Category table to constraint on the values that can be inserted and/or deleted:
CREATE TABLE Name_Category ( name_id INTEGER NOT NULL,
category_id INTEGER NOT NULL,
PRIMARY KEY (name_id, category_id),
foreign key (name_id) references Names(_id),
foreign key (category_id) references Categories(_id));
create two main tables first and then create a junction table in which primary key of both main tables will be available as foreign key.. Primary key of junction table will be union
of primary key of first and second main table.
Create trigger now to automatically insert into junction table...
Also don't forget to create table with cascade deletion and cascade updatation so that any value updated or deleted in main tables will be automatically reflected in junction table

Categories

Resources