Trying to learn Android studio. And I expect your help on this.I am adding and listing data with sqlite.
for example;
id - name - value
1 - john - 100
2 - mark - 200
3 - john - 150
4 - john - 200
5 - adam - 400
what I want to do, list only names one time.
1 - john
2 - mark
3 - adam
private void showlist() {
ArrayList<DataListItems> contactList = new ArrayList<DataListItems>();
contactList.clear();
String query = "SELECT * FROM data ";
Cursor c1 = sqlHandler.selectQuery(query);
if (c1 != null && c1.getCount() != 0) {
if (c1.moveToFirst()) {
do {
DataListItems contactListItems = new DataListItems();
contactListItems.setid(c1.getString(c1
.getColumnIndex("id")));
contactListItems.setName(c1.getString(c1
.getColumnIndex("name")));
contactListItems.setValue(c1.getString(c1
.getColumnIndex("value")));
contactList.add(contactListItems);
} while (c1.moveToNext());
}
}
c1.close();
DataListAdapter contactListAdapter = new DataListAdapter(
SiteList.this, contactList);
lvCustomList.setAdapter(contactListAdapter);
}
You can use the GROUP BY name to select only one name. However, the id selected would be an arbitrary id for each group (name).
your code could use String query = "SELECT * FROM data GROUP BY name";
If you wanted the first/lowest id per name then you could use min(id) in conjunction with GROUP BY NAME.
your code could use String query = "SELECT min(id) AS id, name, value FROM data GROUP BY name";
You say that your expected result should be
1 - john
2 - mark
3 - adam
That would be more complicated (and perhaps of little use) as the id for adam is 5 not 3 (I assume that is simply a typing error).
Following table contains my SQLite-Database on Android:
>>>>> Dumping cursor android.database.sqlite.SQLiteCursor#9f3d273
0 {
id=1543948972569
relationItemID=-1
degree=-1
}
1 {
id=-1
relationItemID=1543948972569
degree=1
}
2 {
id=1543948972569
relationItemID=1543948978808
degree=1
}
3 {
id=1543948978808
relationItemID=1543948972569
degree=-1
}
<<<<<
The SQLite-Query
SELECT id FROM itemsHierarchy
WHERE id = 1543948972569 AND degree BETWEEN 0 AND -128
Returns an empty cursor even though it should find id of first entry.
But if I use '<' instead of 'BETWEEN 0 AND -128' like below, it works.
SELECT id FROM itemsHierarchy WHERE id = 1543948972569 AND degree < 0;
Did I do something wrong or is it a problem of SQLite?
It should be -
SELECT id
FROM itemsHierarchy
WHERE id = 1543948972569
AND degree BETWEEN -128 AND 0
My query is:
String _query = "select DISTINCT Y.CATE_CODE4 CATE_CODE, Y.CATE_NAME4 CATE_NAME,
0 IS_PRESET from G_MASTER X INNER JOIN CATEGORY_VIEW Y ON X.CATE_4 = Y.CATE_CODE4
where X.IS_SALE = 1 AND Y.IS_LOCKED4 = 0 AND Y.CATE_NAME2 not in ('XXXX')";
How does Android SQLite make db.query()?
First of all you should read SQLiteDatabase reference.
You could use a rawQuery(), here's an example of it :
rawQuery - db.rawQuery("select DISTINCT Y.CATE_CODE4 CATE_CODE, Y.CATE_NAME4 CATE_NAME,
0 IS_PRESETG_MASTER X INNER JOIN CATEGORY_VIEW Y ON X.CATE_4 = Y.CATE_CODE4 from table where X.IS_SALE = 1 AND Y.IS_LOCKED4 = 0 AND Y.CATE_NAME2 not in ('XXXX')"",new String[]{"data"});
It's just an example, you have to adapt your code to this.
i run a query with a WHERE
"COMPUTERCLASSROOM_SLOT1 = 0 OR COMPUTERCLASSROOM_SLOT2 = 0 AND COMPUTERCLASSROOM_DONE = 1"
though it return all the row that met a requirement..this is the table rows data
According to column presentation, here are the values of the rows
ROW 1 = 0 0 0
ROW 2 = 1 0 0
ROW 3 = 1 2 1
ROW 4 = 1 3 0
ROW 5 = 1 4 1
ROW 6 = 0 5 1
ROW 7 = 0 0 1
they all return..why is that? if i changed the OR with an AND, it would follow the query, returning ROW 7... its just weird..i need that OR and AND in one query, because my target is to return a row with at least 0 in either SLot1 or Slot2, and DONE = 1
it should be
WHERE (COMPUTERCLASSROOM_SLOT1 = 0 OR COMPUTERCLASSROOM_SLOT2 = 0) AND
COMPUTERCLASSROOM_DONE = 1
As #Jack already pointed out, the problem is because you are not using the parentheses. And hence your query is evaluated logically different from what you are expecting.
Try #JW.'s snippet and it would work perfectly.
WHERE (COMPUTERCLASSROOM_SLOT1 = 0 OR COMPUTERCLASSROOM_SLOT2 = 0) AND (COMPUTERCLASSROOM_DONE = 1)
Underlying cause
AND is evaluated as a multiplication; OR is evaluated as an addition. So according to arithmetic precedence rule (PEMDAS), AND is evaluated before evaluating OR.
Example: 1 OR 0 is 1 + 0 = 1; 1 AND 0 is 1 * 0 = 0;
So
X or X or X and X is grouped automatically as X or X or (X and X).
Use of parenthesis avoids the confusion, as well as makes code more readable.
I'm using the external storage for storing events in a database while they are waiting to be sent to the server.
I'm seeing really bad performance when inserting records.
I know the external memory can be slow but I wanted to see some number so I wrote a small app which tests it.
Here is the code:
public static final int INSERTS = 100;
File dbFile = new File(Environment.getExternalStorageDirectory(), "test.sqlite3");
// File dbFile = new File(getFilesDir(), "test.sqlite3");
dbFile.delete();
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
db.execSQL("CREATE TABLE events (_id integer primary key autoincrement, event_type TEXT NOT NULL, timestamp BIGINT, data TEXT);");
db.execSQL("CREATE INDEX mainIndex ON events (event_type, timestamp ASC);");
InsertHelper helper = new InsertHelper(db, "events");
final int eventTypeCol = helper.getColumnIndex("event_type");
final int timestampCol = helper.getColumnIndex("timestamp");
final int dataCol = helper.getColumnIndex("data");
long start = System.currentTimeMillis();
String eventType = "foo", data = "bar";
long timestamp = 4711;
for(int i = 0; i < INSERTS; ++i) {
helper.prepareForInsert();
helper.bind(eventTypeCol, eventType);
helper.bind(timestampCol, timestamp);
helper.bind(dataCol, data);
helper.execute();
}
long end = System.currentTimeMillis();
Log.i("Test", String.format("InsertHelper, Speed: %d ms, Records per second: %.2f", (int)(end-start), 1000*(double)INSERTS/(double)(end-start)));
db.close();
dbFile.delete();
db = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
db.execSQL("CREATE TABLE events (_id integer primary key autoincrement, event_type TEXT NOT NULL, timestamp BIGINT, data TEXT);");
db.execSQL("CREATE INDEX mainIndex ON events (event_type, timestamp ASC);");
start = System.currentTimeMillis();
ContentValues cv = new ContentValues();
for(int i = 0; i < INSERTS; ++i) {
cv.put("event_type", eventType);
cv.put("timestamp", timestamp);
cv.put("data", data);
db.insert("events", null, cv);
}
end = System.currentTimeMillis();
Log.i("Test", String.format("Normal, Speed: %d ms, Records per second: %.2f", end-start, 1000*(double)INSERTS/(double)(end-start)));
db.close();
dbFile.delete();
The database is exactly as the one my real app is using, I tried removing the index but it made no difference.
Here are the results:
Nexus One, Internal memory
Method | Records | Time (ms) | Records per second
-------------+---------+-----------+--------------------
Normal | 100 | 2072 | 48.26
InsertHelper | 100 | 1662 | 60.17
Nexus One, External memory:
Method | Records | Time (ms) | Records per second
-------------+---------+-----------+--------------------
Normal | 100 | 7390 | 13.53
InsertHelper | 100 | 7152 | 13.98
Emulator, Internal memory:
Method | Records | Time (ms) | Records per second
-------------+---------+-----------+--------------------
Normal | 100 | 1803 | 55.46
InsertHelper | 100 | 3075 | 32.52
Emulator, External memory:
Method | Records | Time (ms) | Records per second
-------------+---------+-----------+--------------------
Normal | 100 | 5742 | 17.42
InsertHelper | 100 | 7164 | 13.96
As you can see the emulator cannot be trusted, InsertHelper should be faster if anything.
This is, of course, to be expected, the test was mostly done out of curiosity.
What have me concerned however is the bad performance on my phone when using external memory, have I missed some crucial aspect of SQLiteDatabase or is it simply so that the SD card will be slow?
I can add that in my real app I've disabled locking and it makes little difference.
CommonsWare is correct in his comment. Something that makes a big difference for db performance is using transactions. Wrap your insert loop in a transaction. I'm not 100% sure if it would work with the InsertHelper but you can try replacing your for loop with this:
db.beginTransaction();
try {
for(int i = 0; i < INSERTS; ++i) {
helper.prepareForInsert();
helper.bind(eventTypeCol, eventType);
helper.bind(timestampCol, timestamp);
helper.bind(dataCol, data);
helper.execute();
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
I have some db performance issues so I used your code to measure the inserts per second on my system. But I also added wrapping in {begin,end}Transaction().
In the emulator. I got:
InsertHelper-Internal-Trans, Speed: 67 ms, Records per second: 1492.54
InsertHelper-External-Trans, Speed: 70 ms, Records per second: 1428.57
Normal-Internal-Trans, Speed: 148 ms, Records per second: 675.68
Normal-External-Trans, Speed: 152 ms, Records per second: 657.89
InsertHelper-Internal-NoTrans, Speed: 514 ms, Records per second: 194.55
Normal-Internal-NoTrans, Speed: 519 ms, Records per second: 192.68
InsertHelper-External-NoTrans, Speed: 590 ms, Records per second: 169.49
Normal-External-NoTrans, Speed: 618 ms, Records per second: 161.81
And on a Samsung Galaxy Note:
InsertHelper-External-Trans, Speed: 52 ms, Records per second: 1923.08
InsertHelper-Internal-Trans, Speed: 52 ms, Records per second: 1923.08
Normal-External-Trans, Speed: 77 ms, Records per second: 1298.70
Normal-Internal-Trans, Speed: 121 ms, Records per second: 826.45
Normal-External-NoTrans, Speed: 4562 ms, Records per second: 21.92
Normal-Internal-NoTrans, Speed: 4855 ms, Records per second: 20.60
InsertHelper-External-NoTrans, Speed: 5997 ms, Records per second: 16.68
InsertHelper-Internal-NoTrans, Speed: 8361 ms, Records per second: 11.96