I am developing an Android application that supports Arabic and English, but I am still confused about the database design:
The approach I am following is
creating a language table that holds two records (Arabic and English)
creating a table that holds normal data (not language specific)
creating a translation table that holds language specific content
For example to implement (Help) I created the following tables:
Language (int id, text Code)
Help (int id)
Help_translation(int id, int Help_id, int Language_id, text Question, text Answer)
I have read this solution so many time, but I still don't know why do we have a separate table for (Help) that does nothing!
Is there something wrong about my approach?
On the face of it, the Language table will appear once in the system. I suggest using the 'll_tt' notation for language and territory based on the ISO country codes (ISO 3166) and ISO language codes (ISO 639-2). Thus, you might have en_gb for British English, en_us for US English, and ar_sa for Saudi Arabian Arabic, and ar_eg for Egyptian Arabic. This may be more powerful than you currently need, but gives you a direction for the future.
Thus, the Language table might have columns:
id integer (autoincrement) Primary key.
code char(5) — Unique.
The Help table in your design is for 'documentation' purposes. It records the valid help numbers that the application can use. A fuller version of the table might include information about the message: where it is used in the application; which version it was introduced in; which version it became obsolete with (or maybe not — we have internationalized message files that have to be good for use with releases over a period of about 10 years); dates associated with the version — or dates instead of the version; and 'notes to the translator' (guidelines for how to translate the message, if any special guidelines are needed).
The minimalistic version of the Help table with just the Help ID number will do for the time being:
id integer (autoincrement). Primary key.
The Help_Translation table stores the strings that the application will display. The id column is of minimal value here; I would omit it (but you can keep it if you wish). The Help_ID column is a foreign key reference to the Help table; the Language_ID column is a foreign key reference to the Language table. For your chosen application, there appears to be both a question and an answer for each help item.
Therefore, the Help_Translation table has the columns:
id integer (autoincrement, optional, not sure when you'll use it).
Help_ID integer — foreign key references Help(ID).
Language_ID integer — foreign key references Language(ID).
Question text — the question in the appropriate language for the given Help_ID.
Answer text — the answer to the question in the appropriate language for the given Help_ID.
Primary key: Help_ID and Language_ID.
An alternative design would have simply a translation table with a 'Message ID' and a 'Language ID' and the translated string (primary key on Message ID and Language ID). There would be a table of Messages, identifying the valid Message IDs plus supporting data of the type outline previously. This might include the default message to be used (untranslated) when there is no translated version of the message for a particular language/territory (or you can make up more complex schemes for handling missing messages, so that when Arabic is requested but the translation for, say, Libya (LY) is incomplete, it falls back onto ar_sa and only then onto en_gb). Your Help table might then contain a Help ID, plus two Message ID values, one for the Question and one for the Answer. The advantage of this scheme is that all translated messages are in a single table.
There are undoubtedly other schemes that could be devised.
Related
At my app I am using a string value with a length of 50+ characters as my "Primary Key" of each object (around 10,000 objects), is there any performance difference in fetching one or many objects where there primary value contains a string of 50+ characters vs object that contain primary key value of lets say a string with 10 characters?
Thank you for the help
There is definitely a big difference in query writing. Because your main key is a long string and the search base in Realm based on Primary Key. You can have a better solution. Consider the following example.
I have a table called product that has the following fields.
ID (Primary Key) // user can't not access it. for backend Logic
product Code // user can access it.for front logic
Product Name
And etc ...
Now I consider the main key as an ID for myself, but I only use the productCode to display to the user.
This method solves both the indexing speed problem (because the length of the main key character is shorter) and my program performance and structure are correct.
Imagine a database table with different food items, e.g. milk. I want the product names to be translated. I want to keep the translations separate from the table and use string resources instead. So my table might look like this:
ID product_name stringRes
1 milk ???
In my app I have #string/milk for the translations. How would I store a reference to #string/milk in the database? R.id.milk is likely not always the same ID value on different compilations, so putting ? R.id.milk` in the table isn't a good idea?
Store your own identifier in the database, and have code in your app to map that identifier to its text representation. Today, that text representation might come from a resource. Next month, it might come from a translation that you download. A month after that, it might come from an label supplied by the user.
You are right, Resource ids are not always same. So, it is not a good idea to refer db column by resource id. Then, for the translation, ideally you should never prepackage the translation if you have dynamic products/items. So for referencing back to the database, ideally you should have a different table where you can map translation like this:
id | product_fk | translated_name | translated_source_iso
world! I am developing an Android project for my Android course at university. I am creating an app about my country. So a user will be able to view our national food, instruments etc. I cannot figure out a good approach for creating a table so that it supports multi languages in android SQLite. My solution for food table:
ID Primary key
Food_name-def VARCHAR(100)
Food-name-ru VARCHAR(100)
Food-desc-def TEXT
Food-desc-ru TEXT.
Is this a good approach for suuporting multi languages for each table(food, instruments etc)?
I would create an extra table for each translatable object. The approach of creating distinct columns is not a good approach for this case.
In your case:
Food:
ID
Food_name (language neutral version)
Food_desc (language neutral version)
FoodTrans:
FoodID
Food_name
Food_desc
Language
For my Android app, I want to save data using sqlite with this format:
name, date, attr1, attr2, attr3,...
These are the requirements:
each date can only contain each name once
there can be a variable number of attributes(numbers) for each name
each specific name has the same number of attributes
The app will be used to track events throughout the day. Events can have zero or more numeric properties.
The questions are: is sqlite the best way to store things here? If so how do I design my database? What other ways are there to store this kind of data?
is sqlite the best way to store things here?
This will depend on a number of other factors, such as how the data will be queried and used, the volume of transactions, data growth and retention, etc. From what you've described, though, SQLite is a great option, offering functionality out-of-the-box that supports some of your requirements directly, and is commonly used in such cases.
If you don't have much experience with relational databases, implementing this functionality may seem difficult at first, but like learning a new language or framework, it will get easier with time.
If so how do I design my database?
Let's step through each of your enumerated requirements...
each date can only contain each name once
SQLite supports the UNIQUE constraint. For example, if your columns were named name and date, you could add the following to your CREATE TABLE statement:
UNIQUE(name, date)
(A more complete CREATE TABLE statement is in the next example below, and it includes this constraint.)
This constraint prevents the insertion of rows with name/date pairs that already exist. Using android.database.sqlite.SQLiteDatabase, if you attempt to insert a row into the table with a duplicate name/date pair, a SQLiteConstraintException will be thrown at runtime. You will need to handle this exception in your java code.
there can be a variable number of attributes(numbers) for each name
This is a textbook case for normalizing the database, putting your data into multiple tables. For example:
CREATE TABLE names (
name_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name TEXT NOT NULL,
date DATETIME,
UNIQUE(name, date));
CREATE TABLE attrs (
name_id INTEGER NOT NULL,
attr_value INTEGER NOT NULL,
FOREIGN KEY(attr_value) REFERENCES names(name_id));
Your queries that retrieve attribute data would then JOIN the two tables. Since you indicated that "Events can have zero or more numeric properties", a LEFT OUTER JOIN might be most appropriate, as it will return names and dates even if there are no attributes.
Here's an example query, by name:
SELECT n.name, n.date, a.attr_value
FROM names AS n
LEFT OUTER JOIN attrs AS a
ON n.name_id = a.name_id
WHERE n.name = 'SMITH'
ORDER BY n.name, n.date, a.attr_value;
This query would return results like the following:
name date attr_value
--------------- ---------- ------------
SMITH 2015-02-13 1027
SMITH 2015-02-13 4426
SMITH 2015-02-13 8390
SMITH 2015-02-20 4426
SMITH 2015-02-20 8152
SMITH 2015-02-20 9328
You can then iterate through and process these results in java. If your results include multiple names and/or dates, then in your loop you should keep track of the last used name and date. If the name/date in the current record is the same, the attribute belongs to the current one. If the name/date is different, then this is a new one.
Note that this approach to your database design is flexible, allowing you to query on the attributes, for instance, to see what name/date pairs are associated.
Also note that there is a FOREIGN KEY constraint on the attrs table, meaning that if you attempt to insert a record into that table with a name_id that does not exist in the names table, a SQLiteConstraintException will be thrown at runtime. You will need to handle this exception in your java code.
each specific name has the same number of attributes
You will need to accommodate this requirement in your java code, probably doing some checks in the database prior to performing an INSERT.
What other ways are there to store this kind of data?
Flat files, JSON, XML, third-party data stores (with their own libraries), to name a few.
I'm not sure but I think the best way to achieve your requirement is to use sqlite and to solve your problem you can have 3 columns only. One for the name and one for the date and the other contains a JSON array that represents the rest of the attributes.
EDIT :
I've followed your good advices and I've used a trie data structure to contain my dictionnary. The structure I have chosen is this one for interested peoples.
But for now I've another issue : the construction of my trie data structure each time I launch my application is very too long ! Maybe my dictionnary is too huge, or maybe the implementation of trie I've chosen is too not appropriate for a simple dictionnary.
So is there a way to conserve this structure even after closing the app like a registered database or if you think the issue is caused by the implementation can you recommend me another one ?
I've got a serious issue with my android's project.
The goal here is to calculate all the words that can be made with a serie of 6 letters
To do that, I've two table in my BDD :
'words' with two columns : '_id'and 'mots'
and 'temp' a temporary table
with the same columns.
'words' contains all the words of vocabulary (it's huge) and 'temp' contains all the possible combinations of letters that can be made with the 6 letters (3 letters used at least).
I'm tryng to select in the table 'temp' the word which are real so the one which are in the table 'words'. Here is my code to do that :
I do a first selection of the words which contain the good letters (at least 3 letters are used)
db.execSQL("CREATE TABLE temp2 (_id integer primary key autoincrement, mots text not null);");
db.execSQL("INSERT INTO temp2 (_id, mots) SELECT * FROM words WHERE mots like '%"+lettres.tab_char.get(0)+"%' OR mots like '%"+lettres.tab_char.get(1)+"%' "
+ "OR mots like '%"+lettres.tab_char.get(2)+"%' OR mots like '%"+lettres.tab_char.get(3)+"%' OR mots like '%"+lettres.tab_char.get(4)+"%' "
+ "OR mots like '%"+lettres.tab_char.get(5)+"%';");
(lettre.tab_char is an ArrayList(Character) which contains the letters used to make the combinations in temp)
I do a join between the tables 'temp2' and 'temp' :
String MY_QUERY = "SELECT temp2._id, temp2.mots FROM temp2 INNER JOIN temp ON temp2.mots = temp.mots;";
Cursor test = db.rawQuery(MY_QUERY, null);
After that I put my values into a listview.
It works but it's really really slow : Can you help me please ?
In general the algorithm that you're using is really quite inefficient. First you're searching through every entry 6 times using a wildcard match, and then you're joining this gigantic result with your entire dataset again.
SQL is probably not the right place to do this. SQL is good at queries, this is more of a calculation. Do the matching in code.
There are lots of ways you can go about accomplishing this, but finding the right solution depends on your requirements. Can the letters repeat? How big of a vocabulary is "huge"? Does it still fit in a few MB? Does this lookup need to happen near-instantaneously?
Update:
Given your requirements, I have to agree with Joe. It's really more of a data structure than an algorithm, but a trie is the way to go. You should be able to build the trie once while loading the app and then each "match" will be a fairly simple lookup walking down the trie.
The algorithm you're looking for is actually called a "trie" (short for retrieval). They are extremely well-suited for this type of calculation (Android actually uses them in the SMS and mail apps to do things like emoticon replacements). If done properly, you will be surprised with the performance you can get from it. I agree with Paul: you definitely should not do the query like you are currently. In fact, many implementations will even load the entire dictionary file into an in-memory trie, and use that trie for word lookup and verification throughout the application's lifetime. The scrabble word list (link is also contained in the question below: twl06.zip) is only 1.9MB, and contains 178k words. The trie in memory should actually be much smaller than 1.9MB, because multiple words will share common prefixes (e.g., "stair" and "stare" will both share the S-T-A prefix, which will then branch off into two leaves ["I" and "R"], and so on...)
Here's a good place to start: Algorithm to generate anagrams