views:

997

answers:

3

For my application, I am trying to add entries without having a duplicate entry, and if there are a duplicate notify the user and have him try again. Using SQLite, which I know very very little about, I have tried these two ways and want to know which one is better, more efficient or a better way to develop it?

First way:

db.execSQL("INSERT INTO " + DatabaseHelper.DATABASE_TABLE + 
"(LATITUDE, LONGITUDE, RATING) SELECT " + latitude + ", " + longitude + ", " + rating +
" WHERE NOT EXISTS (SELECT 1 FROM " + DatabaseHelper.DATABASE_TABLE +
" WHERE LATITUDE = " + latitude + " AND LONGITUDE = " + longitude + ")");

Second way:

 long id = -1;
 try {
  id = db.compileStatement(
    "SELECT COUNT(*) FROM " + DatabaseHelper.DATABASE_TABLE
      + " WHERE LATITUDE = " + latitude
      + " AND LONGITUDE = " + longitude)
    .simpleQueryForLong();
 } catch (NullPointerException e) {
  return -1;
 }
 return id;

The first way, either inserts or ignores the values, I check by doing so, storing the row-count of the rows into a variable before the call, call that function, and then check its results. If the results is not higher than it was before the call, the insert was made ignored, prompt the user with the 'values exist' message. (Very sloppy, I know but desperate times calls for desperate measures)

The second way, returns the actual count of rows that match the numbers I want to store, if the number returned greater than 1, prompt the user with the 'values exist' message.

I have been going back and forth, trying different ways but I do not know how to set up SQLite to have UNIQUE pairs, which I was told would be the easiest. If anyone can correct either of these ways and/or comment on them, that'd be greatly appreciated.

Thanks

+2  A: 

Here's what I understand you want: To have a table Database_Table (not the most descriptive name, if I may say so) which will never allow the same latitude and longitude pair to be entered for two lines.

If correct, you want to declare either a PRIMARY or UNIQUE KEY that incorporates the columns latitude and longitude. If you do so then any attempt to INSERT the same pair will throw an exception, which you can catch and thereby notify the user. Using this technique you will not need to use the WHERE NOT EXISTS (...) clause in your query, just do a plain INSERT and let SQLite alert you to a violation of your UNIQUEness constraint.

If your table already exists, the key can most easily be added using the SQL command CREATE INDEX. Since you may only have a single PRIMARY KEY on any table, if you have a PRIMARY KEY on the table already, you will need to use a UNIQUE KEY for this purpose.

The simplest form of the CREATE INDEX statement you would use is:

CREATE UNIQUE INDEX lat_long_unique ON Database_Table(latitude, longitude)
Larry Lustig
my table isn't actually named Database_Table, its a string constant in my DatabaseHelper class, and I have thought about create index, but I have four fields and I want only two of them unique, can i do so by CREATE INDEX and then just perform a simple INSERT OR IGNORE? And if those are the case, how would SQLite report the UNIQUEness constraint? Thanks in advance.
Anthony Forloney
I know i can use the INSERT OR IGNORE statement on fields if they are unique, which is my case. My way of telling if the value was either inserted or ignored is to store the number-of-rows before the call and compare after, any comments on that?
Anthony Forloney
@Anthony: You create the index including only the two fields you want to be unique. You don't need to count the rows and compare. And don't use OR IGNORE, use either ABORT (the default) or ROLLBACK, depending on how you're using transactions. Using this technique you execute only one command (INSERT) against the database, looking to see whether the error SQLITE_CONSTRAINT is generated. If it is, you tried (and failed) to INSERT a duplicate row.
Larry Lustig
+1  A: 

It seems to me that using a raw lat/long is not a great way to check for duplicates. Each possible lat/long combination using Android's GeoPoint 1E6 format covers an area of something less than five square inches. This size is, of course, different depending on where on Earth you are standing, but it makes a pretty good rule-of-thumb. So you should at least round up your lat/long to the nearest ten, hundred or thousand depending on the size of the thing you want to measure.

Before you store it in the database:

lat = (lat/1000)*1000; 
lon = (lon/1000)*1000;

Here's a good tool for calculating distances between lat/long points on Earth:

http://jan.ucc.nau.edu/~cvm/latlongdist.html

JohnnyLambada
A: 

I have decided to go with my second approach (see above)

Reason being since creating a UNIQUE INDEX seem to not to work for me and proved to be a difficult task for me to accomplish whether that was result from my or SQLite's end.

It's purpose is not trivial, approach may be elementary but it does what I need it to do.

I hope people encountering a situation like this can be influenced by the answers left here and wish they have better luck with it than I had.

Anthony Forloney