How to handle hardcoded stuffs in database and coding - php

There are some language and courses(based on language) are defined in two table. Language table reference is used in course table to relate course with particular language. I also have a notes table that content notes of specific course and that is related to course table. Now I have two issues.
Now in coding I need to take some specific action for Spanish language only. So how should I handle this as languages will be entered by users and we would not be having any idea about Spanish language ID. If I do use text (the language name) then each time I need to fetch ID for Spanish from language table and then will fetch all course related to this from course table.
Suppose Spanish notes are stored in four separate sections and other notes have only one section so should I use same table with four column (one for each section) or use two tables(notes and spanish_notes). Using former way, will leave three column blank for other languages notes. I don't think that is good.

One quick solution to your first issue about multiple languages is to use language codes such as 'en', 'es', 'fr' etc. For instance in your language table you could have both id, code columns but in your content tables you could have a FK with code. So you could either get this lang. code from requests Accept-Language property. or somewhere else.
For second question in terms of normalization it is better to have separate tables for Spanish notes. It is way better for many reasons such as redundancy and dependency concerns.
EDIT: PS. You could also have a look at language codes from here and HTTP Accept-Language from here.

Some inputs:
There could be 2 ways of doing this:
a. When languages are entered by users, use a SELECT dropdown box for accepting user inputs. For each SELECT option, you can set the language name as the text and language id as the value. This way you will know the language ID as
b. You can use MySQL INNER JOIN between "language" and "courses" table, something like:
SELECT *
FROM `language` `l`
INNER JOIN `courses` `c` ON `l`.`language_id` = `c`.`language_id`
WHERE `l`.`language_name` = `spanish`;
I think it's okay to keep all notes for all sections in the single table. So, for the other 3 columns that will only contain Spanish notes, you can set them to accept NULL values
Hope it helps.

Related

Good practice for handling naturally JOINed results across an application

I'm working on an existing application that uses some JOIN statements to create "immutable" objects (i.e. the results are always JOINed to create a processable object - results from only one table will be meaningless).
For example:
SELECT r.*,u.user_username,u.user_pic FROM articles r INNER JOIN users u ON u.user_id=r.article_author WHERE ...
will yield a result of type, let's say, ArticleWithUser that is necessary to display an article with the author details (like a blog post).
Now, I need to make a table featured_items which contains the columnsitem_type (article, file, comment, etc.) and item_id (the article's, file's or comment's id), and query it to get a list of the featured items of some type.
Assuming tables other than articles contain whole objects that do not need JOINing with other tables, I can simply pull them with a dynamicially generated query like
SELECT some_table.* FROM featured_items RIGHT JOIN some_table ON some_table.id = featured_items.item_id WHERE featured_items.type = X
But what if I need to get a featured item from the aforementioned type ArticleWithUser? I cannot use the dynamically generated query because the syntax will not suit two JOINs.
So, my question is: is there a better practice to retrieve results that are always combined together? Maybe do the second JOIN on the application end?
Or do I have to write special code for each of those combined results types?
Thank you!
a view can be thot of as like a table for the faint of heart.
https://dev.mysql.com/doc/refman/5.0/en/create-view.html
views can incorporate joins. and other views. keep in mind that upon creation, they take a snapshot of the columns in existence at that time on underlying tables, so Alter Table stmts adding columns to those tables are not picked up in select *.
An old article which I consider required reading on the subject of MySQL Views:
By Peter Zaitsev
To answer your question as to whether they are widely used, they are a major part of the database developer's toolkit, and in some situations offer significant benefits, which have more to do with indexing than with the nature of views, per se.

Multilanguage Database: which method is better?

I have a Website in 3 languages.
Which is the best way to structure the DB?
1) Create 3 table, one for every language (e.g. Product_en, Product_es, Product_de) and retrieve data from the table with an identifier:
e.g. on the php page I have a string:
$language = 'en'
so I get the data only
SELECT FROM Product_$language
2) Create 1 table with:
ID LANGUAGE NAME DESCR
and post on the page only
WHERE LANGUAGE = '$language'
3) Create 1 table with:
ID NAME_EN DESCR_EN NAME_ES DESCR_ES NAME_DE DESCR_DE
Thank you!
I'd rather go for the second option.
The first option for me seems not flexible enough for searching of records. What if you need to search for two languages? The best way you can do on that is to UNION the result of two SELECT statement. The third one seems to have data redundancy. It feels like you need to have a language on every names.
The second one very flexible and handy. You can do whatever operations you want without adding some special methods unless you want to pivot the records.
I would opt for option one or two. Which one really depends on your application and how you plan to access your data. When I have done similar localization in the past, I have used the single table approach.
My preference to this approach is that you don't need to change the DB schema at all should you add additional localizations. You also should not need to change your related code in this case either, as language identifier just becomes another value that is used in the query.
That way you would be killing the database in no-time.
Just do a table like:
TABLE languages with fields:
-- product name
-- product description
-- two-letter language code
This will allow you, not only to have a better structured database, but you could even have products that only have one translation. If you want you can even want to show the default language if no other is specified. That you'll do programmatically of course, but I think you get the idea.

PHP/MySQL web-app Internationalization with enum DB fields

I have joined a project recently and now I'm working on its Internationalization improvement. Technologies used are PHP/MySQL/Zend Framework/Dojo. I18n is implemented using gettext almost as described here link to SO question in the second answer.
But I encountered one problem. Some part of the information specific to certain DB tables is stored within those tables in the enum type columns. For example there is a field usr_online_status in the table "user" which could be one of either 'online' or 'offline'. There are many such tables with enum fields which contain info like ('yes' ,'no') ,('download', 'upload') and so on. Of course this info is displayed in English regardless of the current Language chosen by user.
I would like to solve this inconvenience. But don't know what is the best way to do this in terms of performance and ease of implementation.
I see two possible options:
1) Make language specific dictionary tables for each table which uses such enums.
2) Download all the info from enums. Translate it. Make a script which could on demand alter every table and replace those enums with the required translations.
But there may be simpler or better solutions for this problem.
What would you do ?
Thanks for your answers.
UPD1
Important remark. Info from the enums is not only displayed at the GUI but is used in search. For example - there is a grid on a webpage which contains info about users. You can type 'line' in a search field and the result will be only those users with the word '%line%' in their info, for example 'online' status.
You definitly want dictionary tables: Only with these can 2 different users of the app work in different languages at the same time.
I recommend to put some of these dictionary tables into PHP though, as this has proven to be quite an unintrusive and performant way of doing it - e.g.
$translation=array('yes'=>'Ja','no'=>'Nein', ..)
//...
$row=mysql_fetch_row($qry);
//$row[1] has yes/no
$row[1]=$translation[$row[1]];
//...
$translation could be require_once()'ed depending on the current user's language preferences, the URL or whatever
Basically you trade some RAM for speed and easyness.
UPDATE:
With Gior312 adding the info about search, here is my solution for it: Have the reverse translation in a DB table (you even might use it to create $translation per a script):
CREATE TABLE translations (
id INT PRIMARY KEY AUTO_INCREMENT,
languageid INT NOT NULL,
enumword VARCHAR(m) NOT NULL,
langword VARCHAR(n) NOT NULL,
-- n and m to your needs
INDEX(languageid)
-- other indices to your needs
)
Now when the search up until now was
$line=... //Maybe coming from $_POST['line'] via mysql_real_escape_string()
$sql="SELECT * FROM sometable WHERE somefield LIKE '%$line%'";
What you now do is
$line=... //Maybe coming from $_POST['line'] via mysql_real_escape_string()
$sql="SELECT enumword FROM translations WHERE languageid=$currentlanguageid AND langword LIKE '%$line%'";
//fetch resulting enumwords into array $enumwords
$enumlist=implode("','",$enumwords);
//This assumes, that the field enumwords contains nothing, that needs to be escaped
$sql="SELECT * FROM sometable WHERE somefield IN ('$enumlist')";
The rationale behind treating forward and back translation differently is:
There will be many more lines in the code where you display, than where you search, so the unintrusiveness of the forward translation is more important
The forward trnslation has to be done PER ROW (with a join), the reverse only PER QUERY, so the performance of the forward translation is more important than the performance of the reverse translation

Suggestion for database structure for multilanguage

Using PHP 5.x and MySQL 5.x
So I asked a question yesterday about the best way of handling dynamic data in multilanguage, this question is what would be a good solution for the database structure to handle this. I have entries in the database for things like stories. My plan is to store a different version of the story for each language available in a db. So if the site supports english and spanish then in the admin tool they can add a english version of a story and a spanish version of a story.
My thoughts on that was to have seperate tables in the db, one for each language. So one story table for english version, one for spanish and one for whatever other languages. Then on the front end I simply allow the visitor to select what language to view the site in and via variables know what table to query to get that version of the story. But one issue is what if there isnt a spanish version but they selected spanish? Is that a good solution or is there a better way of doing this? Looking for suggestions.
Having multiple tables is really not necessary, unless you plan on having millions of stories... I usually go along with two tables; one for the item and another for the localized item
For example, a story would be like
table "story"
id INTEGER (Primary Key)
creation_date DATE_TIME
author VAR_CHAR(32)
..other general columns..
table "story_localized"
story_id INTEGER (Foreign Key of story.id) \
lang CHAR(2) -- (Indexed, unique -- story_id+lang)
content TEXT
..other localized columns..
Performing the query is simply a matter of JOINing the two tables :
SELECT s.*, sl.*
FROM story s
JOIN story_localized sl ON s.id = sl.story_id
WHERE s.id = 1 -- the story you're looking for here
AND sl.lang = 'en' -- your language here
-- other conditions here
This configuration gives a few advantages :
all your data is in the same table, no need to synchronizing CRUD operations
you can add new languages to any story without the need to create yet more tables
etc.
** EDIT **
Just as a bonus, here is a "trick" to retrieve a story easily, regardless of the language it's been written into
SELECT *
FROM (SELECT *
FROM story s
JOIN story_localized sl ON s.id = sl.story_id
WHERE s.id = {storyId}
AND sl.lang = {desiredLanguage} -- example : 'es'
UNION
SELECT *
FROM story s
JOIN story_localized sl ON s.id = sl.story_id
WHERE s.id = {storyId}
AND sl.lang = {defaultLanguage} -- example : 'en'
UNION
SELECT *
FROM story s
JOIN story_localized sl ON s.id = sl.story_id
WHERE s.id = {storyId}
LIMIT 1 -- ..get the first language found
) story_l
LIMIT 1 -- only get the first SELECTed row found
Will try to fetch the story in the {desiredLanguage}, if the story is not available in that language, try to find it in {defaultLanguage} (ie. the site's default language), and if still nothing found, it doesn't matter which language to fetch the story, then, so fetch the first one found. All in one query, and all you need are 3 arguments: the story id, the desired language, and a default fallback language.
Also, you can easily find out in what language the story is available into with a simple query :
SELECT sl.lang
FROM story_localized sl
WHERE sl.story_id = {storyId}
The best way to do this is to store the story as a multi-valued attribute. As #Yanick has shown you.
And it would be interfacially better if you populate your language choice element only with those languages in which that story is available.
Another nice approach when it is not a long text: weeks names, monts... in my app I am localizing musical genres, and musical instruments. Use a text field for store json data.
So in my musical "genres" table, there is a text field named "lang". On in I have the following json structure:
{"es_gl":"MARCHA ESPAÑOLA", "es_EN" : "SPANISH MARCH"}
Then using PHP is really easy to get our data from a json structure. Let's say I have a genre on my $genre variable.
$myJSON = json_decode($genre->lang);
echo $myJSON->es_gl // This echoes MARCHA ESPAÑOLA
echo $myJSON->es_es // This echoes SPANISH MARCH
This is good solution when your localization data is not big... like posts or blogs.

MySQL naming conventions, should field name include the table name?

A friend told me that I should include the table name in the field name of the same table, and I'm wondering why? And should it be like this?
Example:
(Table) Users
(Fields) user_id, username, password, last_login_time
I see that the prefix 'user_' is meaningless since I know it's already for a user. But I'd like to hear from you too.
note: I'm programming in php, mysql.
I agree with you. The only place I am tempted to put the table name or a shortened form of it is on primary and foreign keys or if the "natural" name is a keyword.
Users: id or user_id, username, password, last_login_time
Post: id or post_id, user_id, post_date, content
I generally use 'id' as the primary key field name but in this case I think user_id and post_id are perfectly OK too. Note that the post date was called 'post_date" because 'date' is a keyword.
At least that's my convention. Your mileage may vary.
I see no reason to include the table name, it's superfluous. In the queries you can refer to the fields as <table name>.<field name> anyway (eg. "user.id").
With generic fields like 'id' and 'name', it's good to put the table name in.
The reason is it can be confusing when writing joins across multiple tables.
It's personal preference, really, but that is the reasoning behind it (and I always do it this way).
Whatever method you choose, make sure it is consistent within the project.
Personally I don't add table names for field names in the main table but when using it as a foreign field in another table, I will prefix it with the name of the source table. e.g. The id field on the users table will be called id, but on the comments table it, where comments are linked to the user who posted them, it will be user_id.
This I picked up from CakePHP's naming scheme and I think it's pretty neat.
Prefixing the column name with the table name is a way of guaranteeing unique column names, which makes joining easier.
But it is a tiresome practice, especially if when we have long table names. It's generally easier to just use aliases when appropriate. Besides, it doesn't help when we are self-joining.
As a data modeller I do find it hard to be consistent all the time. With ID columns I theoretically prefer to have just ID but I usually find I have tables with columns called USER_ID, ORDER_ID, etc.
There are scenarios where it can be positively beneficial to use a common column name across multiple tables. For instance, when a logical super-type/sub-type relationship has been rendered as just the child tables it is useful to retain the super-type's column on all the sub-type tables (e.g. ITEM_STATUS) instead of renaming it for each sub-type (ORDER_ITEM_STATUS, INVOICE_ITEM_STATUS, etc). This is particularly true when they are enums with a common set of values.
For example, your database has tables which store information about Sales and Human resource departments, you could name all your tables related to Sales department as shown below:
SL_NewLeads
SL_Territories
SL_TerritoriesManagers
You could name all your tables related to Human resources department as shown below:
HR_Candidates
HR_PremierInstitutes
HR_InterviewSchedules
This kind of naming convention makes sure, all the related tables are grouped together when you list all your tables in alphabetical order. However, if your database deals with only one logical group of tables, you need not use this naming convention.
Note that, sometimes you end up vertically partitioning tables into two or more tables, though these partitions effectively represent the same entity. In this case, append a word that best identifies the partition, to the entity name
Actually, there is a reason for that kind of naming, especially when it comes to fields, you're likely to join on. In MySQL at least, you can use the USING keyword instead of ON, then users u JOIN posts p ON p.user_id = u.id becomes users u JOIN posts p USING(user_id) which is cleaner IMO.
Regarding other types of fields, you may benefit when selecting *, because you wouldn't have to specify the list of the fields you need and stay sure of which field comes from which table. But generally the usage SELECT * is discouraged on performance and mainenance grounds, so I consider prefixing such fields with table name a bad practice, although it may differ from application to application.
Sounds like the conclusion is:
If the field name is unique across tables - prefix with table name. If the field name has the potential to be duplicated in other tables, name it unique.
I found field names such as "img, address, phone, year" since different tables may include different images, addresses, phone numbers, and years.
We should define primary keys with prefix of tablename.
We should use use_id instead if id and post_id instead of just id.
Benefits:-
1) Easily Readable
2) Easily differentiate in join queries. We can minimize the use of alias in query.
user table : user_id(PK)
post table : post_id(PK) user_id(FK) here user table PK and post table FK are same
As per documentation,
3) This way we can get benefit of NATURAL JOIN and JOIN with USING
Natural joins and joins with USING, including outer join variants, are
processed according to the SQL:2003 standard. The goal was to align
the syntax and semantics of MySQL with respect to NATURAL JOIN and
JOIN ... USING according to SQL:2003. However, these changes in join
processing can result in different output columns for some joins.
Also, some queries that appeared to work correctly in older versions
(prior to 5.0.12) must be rewritten to comply with the standard.
These changes have five main aspects:
1) The way that MySQL determines the result columns of NATURAL or USING join operations (and thus the result of the entire FROM clause).
2) Expansion of SELECT * and SELECT tbl_name.* into a list of selected columns.
3) Resolution of column names in NATURAL or USING joins.
4) Transformation of NATURAL or USING joins into JOIN ... ON.
5) Resolution of column names in the ON condition of a JOIN ... ON.
Examples:-
SELECT * FROM user NATURAL LEFT JOIN post;
SELECT * FROM user NATURAL JOIN post;
SELECT * FROM user JOIN post USING (user_id);

Categories