I'm using sugar orm for a high scores database, and after a lot of searching(because the documentation is very pure and also some links are dead), I've managed to save and list the records from the database. Unfortunately I cannot find out how to delete the duplicated score records, or how to update a record instead of saving a new one in case the name and high score values are the same.
I found that this can be done with something like this:
getWritableDatabase().execSQL("delete from highscores where _id not in (SELECT MIN(_id ) FROM highscores GROUP BY highscores_id)");
}
but how can I do it with sugar orm in which I don't know if it even has a id field or its name ?
UPDATE:
Following #Juancortes' s advice I'm trying to check for the current player, if the current score exists in database, before add the record:
private void saveScore(){
int total;
total=checkList();
if(total>0) {
HighScoresDB highScores = new HighScoresDB(tvPlName.getText().toString(), total);
highScores.save();
}
}
private int checkList(){
String tempName=tvPlName.getText().toString();
List<HighScoresDB> check = HighScoresDB.find(HighScoresDB.class, "person = ?",tempName);
ArrayList<Integer> templist = new ArrayList<Integer>();
for(int i=0;i<check.size();i++){
templist.add(check.get(i).score);
}
int total = Integer.valueOf(totalPts.getText().toString());
if(templist.contains(total)) {
total = 0;
}else{
total=Integer.valueOf(totalPts.getText().toString());
}
return total;
}
I get a list with the existing records for current player using sugar orm. After I'm checking if the list contain the current score value, and if is true I set it to "0". Then in "saveScore()" method I save a record only if the score value is greater that "0". But this doesn't work and I keep getting double, triple etc records. What I'm doing wrong?
UPDATE 2:
Seems that "contains" doesn't work for the list with the database objects directly. So I created an ArrayList with only the scores(code updated too), and I used that list to check if the total exists. Now seems that works fine and don't created double records.
A little late, but you can use the executeQuery() method for a raw custom query. Here is an example of a query that will remove duplicates:
DELETE tableName FROM tableName LEFT OUTER JOIN(
SELECT MIN(table_primary_key) AS rowId, col1, col2, col3
FROM tableName
GROUP BY col1, col2, col3
) as KeepRows ON tableName.table_primary_key = KeepRows.rowId
WHERE KeepRows.rowId IS NULL
Compares all the rows, finds any duplicates, deletes them.
This will execute in SQL without having to pull back all the records, though you can modify it to a SELECT and then use the SugarORM delete functionality. That will increase memory usage though.
Related
I am fetching a string from Database using the column id. When I enter a query in SQLite DB Browser it returns what is need but the same query returns nothing when coded through Java.
My Data Base contains a table named drugs which has 3 columns i.e. drug_id, drug_name and drug_overview. Using drug_id i am fetching drug_overview. I have tried the query in db browser which returns me the correct string from drug_overview but the same query returns nothing when coded through java.
SQLite DB Browser query:
SELECT * FROM drugs Where drug_id = 50;
JAVA CODE:
String query105 = "SELECT * FROM drugs Where drug_id = " + drug_id;
Log.e("TESTDB1","Drugs table query: " + query105);
Cursor c105 = db.rawQuery(query105,null);
if (c105 != null){
while (c105.moveToNext()){
String overview = c105.getString(c105.getColumnIndexOrThrow("drug_overview"));
Log.e("TESTDB1","Overview: " + overview);
}
c105.close();
}
Expected result is Overview: Acyclovir is an antiviral drug. It slows the growth and spread of the herpes virus in the body. It will not cure herpes, but it can lessen the symptoms of the infection.Acyclovir is used to treat infections caused by herpes viruses, such as genital herpes, cold sores, shingles, and chicken pox, as well as varicella (chickenpox), and cytomegalovirus.Acyclovir may also be used for purposes not listed in this medication guide.
But the actual result is Overview:
empty
. When i change the id in my query it gives the correct result from a different drug.
I am afraid that your problem may be with the actual data itself as Mike said in comment, I think your database in the files is old and you haven't copied the latest to folder. Try to re-install and delete old database
Your query returns 0 or 1 lines so I think you should use c105.moveToFirst() instead of c105.moveToNext(). moveToNext is supposed to be used for a list, not for a single entry. Do something like:
if (c105.moveToFirst()){
String overview = c105.getString(c105.getColumnIndex("drug_overview"));
// do something with the result
}
c105.close();
Scenario is like
Before inserting into sqlite db I have to check whether is it reached a particular number, say 10. I know it can be done by using 2 queries for get and insert.
Can it be done in 1 query in android and sqlite
INSERT INTO Customers (name, age)
SELECT 'MM', 20 WHERE (SELECT count(*) from Customers) < 10;
By use this query, we only insert new customer to database when total customers in database < 10
Considering the documentation for INSERT you can also insert a result of a select statement. So instead of inserting the values directly, you could assemble a select statement to only return your default values with coalesce if and only if a condition for the count yields true.
This is mostly an idea and theoretical approach, but worth trying.
To check how many rows in database, you need to make
select * from
query and get the cursor object. Cursor object have getCount method which return you size of cursor, its simply means to show all your records in table.
Cheers!!!
I fetch records in my SQLite database like this.
spellId = extra.getString("spellId");
DBase db = new DBase(this);
db.open();
String[] data = db.getRecord(Integer.parseInt(spellId));
db.close();
Can I get random data like this without using raw queries and cursor?
try like this:
db.rawQuery("SELECT * FROM mainTable ORDER BY RANDOM() LIMIT 1", null);
You can use Random#nextInt() like
String[] data = db.getRecord(new Random().nextInt(num));
where num falls in the range of your record IDs. You would need to adapt this solution in case your Ids are fragmented and do not form a consecutive range.
One of the ways to do that would be to first create a query to fetch all the primary keys and store the values in a set somewhere. Then pick a random key by generating an index using Random.
String[] data = db.getRecord(IDSet.get(new Random().nextInt(IDSet.size())));
Check out the docs for more information.
Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random number generator's sequence.
If you're considering a DB query solution
A better alternative to using ORDER BY RANDOM() (which is known to not scale well as the number of rows in your table grows) is to let SQLite return a random row using an OFFSET.
First save the total number of rows num somewhere.
SELECT COUNT(*) AS num FROM spells;
Then choose a random number rnum between (0, num) using Random and use the query
SELECT * FROM spells LIMIT 1 OFFSET rnum;
Anyone know of a way to limit the number of rows deleted when using an sql DELETE statement?I just need to delete a row that holds a certain value one time instead of deleting every instance of the value. It's my understanding that the LIMIT clause cannot be added to DELETE statements in SQLITE. Now, I can't see a way to limit the number of rows deleted just using _id because I don't know what row _id will be deleted ahead of time; the rows are being deleted based on a value held in a variable and they could be anywhere in the DB. I hope this makes sense. Here's the delete statement:
String sql = "DELETE FROM strategyTotal WHERE strategy_prices = (?)" ;
db.execSQL(sql, new Double[] {subtractedStrategyPrice });
Use a subquery:
String sql = "DELETE FROM strategyTotal WHERE _id IN (SELECT _id FROM strategyTotal WHERE strategy_prices = (?) LIMIT 1);" ;
db.execSQL(sql, new Double[] {subtractedStrategyPrice });
delete from tablename where rowid in (
select rowid from tablename condition LIMIT 1)
try above work around or you may need to enable SQLITE ENABLE UPDATE DELETE LIMIT
my query is just an example. replace it with your own query.
I have put an sqlite database in my assets folder and imported it onto the phone.
I created an object with multiple properties and when I create a list of that object and assign each property a value from a column of the table they get mixed up
Below is my code
public ArrayList<Exercise> getExercisesFromQuery(String Query) {
ArrayList<Exercise> ExerciseList = new ArrayList<Exercise>();
Cursor cursor = mDb.rawQuery(Query, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Exercise e = new Exercise();
e.setID(Integer.parseInt(cursor.getString(0)));
e.setName(cursor.getString(1));
e.setMuscle(cursor.getString(2));
e.setDescription(cursor.getString(3));
e.setFilepath(cursor.getString(4));
e.setSets(cursor.getString(5));
e.setReps(cursor.getString(6));
e.setEquipment(cursor.getString(7));
e.setPrimaryMuscle(cursor.getString(8));
e.setSecondaryMuscle(cursor.getString(9));
e.setDifficulty(cursor.getString(10));
// Adding contact to list
ExerciseList.add(e);
} while (cursor.moveToNext());
}
return ExerciseList;
}
The current problem is when I do object.getName it gives me the muscle and if I do object.getmuscle it is blank and there is no value but if I do object.getDescription it works fine.
It is not a problem with the database it works fine in any sqlite manager.
Any ideas as to what is wrong?
The reason why the columns are not being returned in the order you expect is not clear. They should come back in the order specified in your query or in the order they are on the table if you are doing SELECT *. However it is not really necessary to address that specific puzzle.
A more defensive and maintainable coding approach is to request each column's index from the cursor by using the getColumnIndexOrThrow method instead of hardcoding them. For example:
int ID_INDEX = cursor.getColumnIndexOrThrow("_id");
int NAME_INDEX = cursor.getColumnIndexOrThrow("name");
If the column doesn't exist you'll get an exception. If it does, you now have its index within the cursor which you can use in the calls to cursor.getString:
e.setID(Integer.parseInt(cursor.getString(ID_INDEX)));
e.setName(cursor.getString(NAME_INDEX));
So you no longer need to worry about what order the columns come back in and you won't need to change any hardcoded index values if your query changes in the future.
Make sure that the columns in the database are in the correct order - column Name should be the second column, column Muscle should be the third column.