Beginning android: how to map a string to a list - android

I just finished the NotepadV1-3 tutorial for Android apps, and I was thinking of creating my own inventory app for fun, which for now basically consists of a list of names (such as "DVD" or "Grocery"), each of which can be clicked, which will bring up another specific list associated with that name. However, with the SQLiteDatabase.insert(..) method, the ContentValue can only take (among many others) "String, String" as argument, and I can't figure out how to input into the database a list of Strings associated with a particular key. I'm having trouble researching on how to resolve this as I am not that familiar with SQL.
What would be the best way to store a key with its associated list of Strings?
Any pointers and suggestions are appreciated!
Android newb :[

The best thing you could is to make a database-design that doesn't need you to input the list as as "string of strings". You might (I have not thought this trough all the way) have a table with lists (id and listName) and another table with contents (id and contentName) and finally a table that connects the two (tableId and contentName).
If you REALLY want to store that string-of-strings, you could serialize it into one string, and then when you've read it from the db, you can rebuild the string. This is NOT recommended though.
Example for a (simpler) database
Table 1 "lists": listId, listName
Table 2 "items": itemId, itemName, listId
e.g.:
Lists:
listId listName
1 DVD's
2 Grocery
Items
itemId itemName listId
1 film1 1
2 film2 1
3 sugar 2
4 milk 2
You can find all items of the grocery list by:
SELECT i.itemName
FROM lists l
JOIN items i ON l.listId = i.listId
WHERE l.listName='Grocery'

Related

How do I create a many-to-many DB schema that also keeps an order for the items associated?

Forgive me if this is fairly simple, I'm new at databases and couldn't find any answers through searching.
I'm looking to create a DB for an android app where there are a number of workouts and each workout has a number of drills. I know I need to create a joint/association table, but the problem is I also need to keep the drills in a certain order and store reps for each drill based on the workout and I'm not really sure how.
Right now I have the three basic tables outlined, but I'm not really sure how to add order and reps.
Current tables:
Workouts: id, name, description
Drills: id, name, description,
WorkoutsDrills: Workout_id, Drill_id
Missing info: reps_for_drill, order
The output I'd like to get is when I pull a workout, I pull a list of drill_IDs, along with some information to put them in order. I also need to get the number of reps for each drill, but the reps are not static to the drill, they are assigned to each drill based on the workout.
Right now I just pull a list of random drills, with no reps stored. If I store the reps in the drill db, then I need a new drill for each instance of a different amount of reps.
sample data
I guess here's some sample data to help explain.
Drills
Name Description
Pushups standard pushup
Situps standard situp
Jumping Jacks standard jumping jack
Workouts
Name Description Drills in a workout(reps)
workout1 sample description Pushups(10), Situps(5)
workout2 sample description2 situps(5), Jumping Jacks(20)
So after some trial and error, I figured out a solution. Ended up being pretty simple. Here are the tables and classes I used.
Classes
I had two classes: Drill and Workout. The only methods they had were getter and setter methods. Below are their fields.
Drill
private String mDrillName;
private String mDrillDescription;
private int mDrillReps;
Workout
private String mWorkoutName;
private String mWorkoutDescription;
private ArrayList<Drill> mDrillList;
Tables
I ended up going with the three tables, one for storing general info on each object and an association table for storing their relations.
Drills
INT : _ID
TEXT : Name
TEXT : Description
Workouts
INT : _ID
TEXT : Name
TEXT : Description
workoutdrill
INT : W_ID //workout ID
INT : D_ID //Drill ID
INT : orderNum //Keeps track of the order of drills in the workout
INT : reps //Keeps track of the number of reps to do for a drill
I haven't fully implemented the usage of the DB yet, I'll come back and put that code in here when I have. My plan to pull the info and populate a workout object, based on a workout_ID number is:
Query the workout table for basic info from the row and populate name and description fields of a workout object.
Query a associationCursor from the workouts table containing all rows that match the specific workout ID number in the W_ID column.
Go to first (or next) line of the associationCursor
Take the drill_ID number and query it from the drills table to return a drillCursor.
Use the two cursors to populate a new tempDrill. (name and description from drillCursor and rep from associationCursor.
Push this temp drill into the ArrayList of the workout.
Repeats steps 3-6 till associationCursor is at the end.
After that, a workout Object should be fully populated with information and usable for what ever is needed.
Please feel free to suggest improvements.

Android ListView with Many-To-Many relationship

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.

Dynamically creating tables in SQLite with user input in Android

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.

Dynamic Tables in Android SQLite

My question involves databases - The scenario is this:
I have an app that tracks when people borrow items. I have an existing table which tracks who they are, what they have borrowed and so on. What I would like to do is create a separate table to track what the person has borrowed, their contact info, if they returned it, etc.
My idea to do this would be to create a Dynamic table in SQL that would hold the records for 1 person, ie
John Smith
DVD; July 12, 2012; Returned in good condition; etc
As I'm still learning, I wanted to know if:
This is possible, feasible or if there is a smarter way of going about it.
Your answer depends on your scenario;
If you are only interested with "who" borrowed "what" (currently) and not "when" except last occurance, and you are assuming there are always only 1 copy of an item, then you can use one to one relation as:
CREATE TABLE Person
(
PersonId int IDENTITY(1,1) NOT NULL,
Name nvarchar(30) NOT NULL,
Surname nvarchar(30) NOT NULL,
BorrowItemId int NULL FOREIGN KEY REFERENCES Item UNIQUE,
BorrowDate datetime NULL,
ReturnDate datetime NULL,
ReturnCondition nvarchar(50) NULL,
CONSTRAINT PK_Person PRIMARY KEY CLUSTERED (PersonId ASC),
)
CREATE TABLE Item
(
ItemId int IDENTITY(1,1) NOT NULL,
ItemDescription nvarchar(50) NOT NULL,
CONSTRAINT [PK_Item] PRIMARY KEY CLUSTERED (ItemId ASC)
)
If you have multiple copies of each item you should remove the UNIQUE key on BorrowItemId changing relation to one to many. In case;
To see the items borrowed and returned with person information:
SELECT PersonId, Name, Surname, ItemDescription, ReturnDate, ReturnCondition
FROM Person INNER JOIN Item
ON BorrowItemId = ItemId
WHERE BorrowItemId IS NOT NULL
AND ReturnDate IS NOT NULL
You can add PersonId filter in WHERE clause to query for specific person
This isn't a good design since you can insert records without date information or you can even have records with date info but no related BorrowItemId. I suggest using many to many and keep historic data (can be handy) or overwrite using update each time the person borrows a new item
Their contact information could be linked into the table which tracks who they are.
If you have not created a table yet for the returns then I suggest you reference the borrowing table's ID and set in the borrowing table a flag to say this item has been returned.
I am not too sure why you would want to create a new table to collate all the information. If you want to get all the information together then I suggest using the SQL keywrod JOIN when preparing statements. If you really want to store the information later on in a table you can but it will just be duplicates in your database.
A tutorial on the different types of joins you can do : http://www.w3schools.com/sql/sql_join.asp
It is definitely possible to do as you describe. It really isn't a very good strategy, though. Your new table is, exactly, equivalent to an additional column in the existing table that tags the row as belonging to a specific individual.

Android's SimpleCursorAdapter with queries using DISTINCT

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

Categories

Resources