first question to SO, so please let me know if I'm stepping on any toes :)
This is a simplified version of my database:
CREATE TABLE products (_id INTEGER PRIMARY KEY, name STRING);
CREATE TABLE product_tag (product_id INTEGER, tag STRING, PRIMARY KEY(product_id, tag));
In one of my activities, I would like to list all products (one row per product) with all tags contained in the row, e.g.
bananas [yellow] [fruit]
ketchup [condiment] [red] [tomato]
mustard [yellow] [condiment]
The options I have considered are:
Using a SimpleCursorAdapter to list all products, querying product_tag in the ViewBinder for each row, and programmatically creating views for each tag and inserting them into the row.
Querying products LEFT JOIN product_tag ON products.id = product_tag.product_id, resulting in one row per tag (or one row per product with no tags) and manually populating the list. This seems more complicated and hacky, and duplicates some data, but avoids querying the db for each row in products.
I'd love it if someone more experienced with Android could comment on the most efficient way to accomplish this! Thanks in advance.
Definitely #2. Database access is slow, so you want to minimize the number of database queries.
Related
I have some kind of this table.
The question is what is the best way to create this kind of table?
Should I create for each item one table is it possible to create only one table??
Updated: See comments under #Emil.
You should have 1 tables as #Emil has suggested.
This should look like, soemthing like
_id, sort, grade, diameter, length, price1_dol, price1_euros, price2_dol, price2_euros, final,
Note: I have split up prices columns up - so you have price1_dol, price1_euros, price2_dol, price2_euros.
It is indeed possible to make this data into just one table. The columns sort and grade seem to uniquely identify one row so together they might make up a candidate key. If so you could use those as your primary key, or create a new integer column that you use as the primary key.
You should definitely not create one table per item. The database schema should never change with normal use. Only when you add, remove or change the type of data you have in your database should you consider changing the schema. Otherwise you should design and normalize your database in such a way that it's possible to grow the data only by inserting new rows, not new tables.
I have:
Three tables: products, orders and order lines.
A CursorLoader and a CursorAdapter: ProductsOrderLoader and ProductsOrderAdapter.
ListView: a simple products listview.
For the time being, my list view shows products bought in a certain order (order lines), plus the rest of the products.
But these items are sorted by productName. What I want is to sort these products by quantity, however the quantity column belongs to another table orderLine.
Is it possible to stick to using CursorLoader and achieve the sorting of listview using a column present in another table?
I found an answer here: Get all the products, and putting a specific order's product first using only orderBy, without having to modify the ContentProvider.
I'm quite new to Android and the SQLite. I'm currently working on an app which requires user to create list of their favourite artists.
I have implemented some charts which already display this artist data. I believe I can easily figure out how to implement adding data to lists.
I was thinking of having two separate tables in SQLite :
Lists (which would store the list names which the user has created)
ChartItems (which would store the chart items and the lists they belong to)
However the Lists table only needs one field in this case "ListName" so I thought it might not be crucial to have a table for this.
Is it possible to dynamically create tables when getting input from a user?
For example : A user creates a list and that value is subsequently used to create a table.
Thanks.
You don't want to be creating new tables on the fly. Your proposal for two tables is fine. The list table should have at least two fields - an integer field called id or _id which is the primary key, and a text field for the list name. The Chartitems table will have a field (listid) which holds the id of the list to which it belongs. This means a chartitem can belong to only one list, and adding a chartitem to a list is achieved by setting the listid field in its record. This is a one-to-many relationship.
If you want to have a single chartitem in more than one list, then you need a many-to-many relationship, which is implemented by having a third table (links). This table will have one field mapping to a list (listid), and one field mapping to a chartitem (itemid.) To add a chartitem to a list, you create the appropriate link entry in the links table. In this case the chartitem table does not need the listid field.
I suggest reading up some more on relationships in databases to clarify these concepts. One principle I strongly suggest following is to have every table contain a field called id which is the primary key for that table, and use that for all references from other tables. In the long run this works much better than using other fields (like name) in relationships.
Here's an interesting question that I'm shocked hasn't been asked more often on the internet. Android's CursorAdapters are extremely useful once you get a ContentProvider up and running and learn how to use it, but they are limited due to their requirement on having the _id field as part of their query (an error is thrown without it). Here's why:
My specific problem is that I have two spinners: One spinner should contain unique "category" names from the database, and the other should populate with all the database entries from the selected "category" (category being the column name, here). This seems like a pretty simple setup that many programs might use, no? Trying to implement that first spinner is where I've run into problems.
Here's the query that I would like for that first spinner:
SELECT DISTINCT category FROM table;
Making this query throws an error on CursorAdapter because the _id column is required as part of the query. Adding the _id column to the projection naturally returns every row of the table, since you're now asking for distinct id's as well, and every id is distinct (by definition). Obviously I would rather see only one entry per category name.
I've already implemented a work around, which is to simply make the query above and then copy the results into an ArrayAdapter. My reason for this post is to see if there was a more elegant solution to this odd little problem and start a discussion on what I could be doing better. Alternate implementation suggestions, such as using different kinds of controls or adapters, are very welcome.
Here's the query I ended up with:
SELECT _id, category FROM table_name GROUP BY category;
I used the rawQuery() function on an SQLiteDatabase object to carry this out. The "GROUP BY" piece was the key towards getting the right results, so thanks to user Sagar for pointing me in the right direction.
Do consider user Al Sutton's answer to this question as well, as it may be a more elegant solution to this problem.
Thanks everyone!
I'd suggest having a separate table with just _id & category in it which contains one row per unique category. Your data rows can then replace their category field with the _id from the category table.
This has the added advantage you can change the category in the categories table and it will show up in all entries in that category.
SELECT DISTINCT category,_id FROM table GROUP BY category;
I think this should give you what you are looking for. The results from this will be the category, and the first _id for that category. You can ignore the second column (_id).
You can specify an _id field alias in your select statement that is just a constant value, for example:
SELECT DISTINCT 0 _id, category FROM table;
Better yet, I solved this problem by using:
SELECT DISTINCT category AS _id FROM table
Now, you have a column with the name _id which has what you want in it
In my application I have a sqlite database that looks like this:
CREATE TABLE notes (_id integer primary key,
content text);
CREATE TABLE tags (_id integer primary key,
name text,
noteid integer,
foreign key(noteid) references notes(_id));
I'm storing text that can have some tags associated with it. Now I want to show this text and the tags in a ListView. However I can't figure out how to do this with a SimpleCursorAdapter. Is it even possible? My data might look like this:
sqlite> select * from notes;
1|foo bar baz
sqlite> select * from tags;
1|x|1
2|y|1
The query to get all notes and the data it returns looks like this:
sqlite> select notes._id, notes.content, tags.name from notes, tags where notes._id = tags.noteid;
1|foo bar baz|x
1|foo bar baz|y
Now, if I want to bind this data to the ListView in some way, how to do it? I would be happy if each row int the ListView contained two lines, one line with the content and one line with all the tags. Am I correct in guessing that the SimpleCursorAdapter won't help me here? What should I do instead?
SimpleCursorAdapter alone can't help you here.
If your goal is that you want one row to be one note + all its tags, you can try overriding bindView() in SimpleCursorAdapter and pouring in the tags that way. That would imply that you have already built up some sort of HashMap of note->tags and therefore can quickly determine the tags to go in the row.
To build up the HashMap, you have two choices that I see:
Build them on the fly by looking up the note in the HashMap, then doing a query to get the tags for that note if they're not found, caching them in the HashMap for later reuse (e.g., scrolling). The catch here is that you're doing a bunch of little queries (bad) and doing them on the main application thread while the user is scrolling (really bad).
Do one big query using an IN clause to get all tags for all notes, and convert the resulting Cursor into a fully-populated HashMap. Then, your per-row lookups will all succeed. This works well if you only have a modest number of rows; otherwise, this query may take longer than the user has patience for.
If your schema is flexible, you might consider whether you are better served with some amount of denormalization, such as having the tags in a single column of the notes table via a comma-delimited list or something. Even if that complicates write operations (e.g., putting tags in two places), if your reads greatly outnumber your writes, it may be worth it.