Store data in MySQL or a PHP file? - php

I am working on a project and I ended up with the table below:
+---------------+--------------+------+-----+--------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+--------------------+-------+
| id | int(11) | NO | MUL | NULL | A_I |
| user _id | int(11) | NO | | NULL | |
| info | varchar(255) | NO | | NULL | |
| country | tinyint(3) | NO | | NULL | |
| date_added | timestamp | NO | | 0000-00-00 00:00:00| |
+---------------+--------------+------+-----+--------------------+-------+
Because I wanted to avoid storing countries as varchar all the time I thought I should use number IDs instead. My question is, would it be better to store the country IDs in a table where I would give a name to each one of them or do that in a php file? Countries won't change or anything. It will be a list of around 100 countries.
Thanks!

Use a seperate country table.
countries table
---------------
id
name
Then you can relate to the country ID in your table. That way you make sure only countries from your list are added and you don't need to store strings everywhere and you can easily change country names or addnew ones.

Related

Mysql speed: table with many columns or 2 tables using a join

I tried searching for this but I could not find anything about this but design choices.
So my question is like the title. What is faster? Create 1 table with many columns or create 2 or 3 (for many to many) tables with join(s).
I like the idea of have multiple tables so the data is separated. Mostly for many to many like data. But my friend told me having 5 columns with boolean is just fine. But I like the idea of have a table with the settings and then a table between with user.id and setting.id. But my question is also, does it have a impact on the query?
example:
Users
- id
- Email
- SettingA
- SettingB
- SettingC
OR example:
Uers
- id
- email
Users_Settings
- user_id
- setting_id
Settings
- id
- someSettingsValue
What woult be faster for Mysql to query the data? (retrieving settings for user)
not at all.. Only joins between 2 r 3 will take time compared to single table fields.
It's not about preferring single table with many columns or preferring multiple tables. It's about Normalization.
According to your provided schema, if all users will always have three settings, i.e. Setting A, B and C, then it's better to create single table with these three columns for settings.
users table:
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| Email | varchar(128) | NO | | NULL | |
| SettingA | tinyint(1) | NO | | NULL | |
| SettingB | tinyint(1) | NO | | NULL | |
| SettingC | tinyint(1) | NO | | NULL | |
+----------+--------------+------+-----+---------+----------------+
But if any of the setting is saved is null, then better is to create separate table for settings and then a pivot table for maintaining users' settings without primary key.
users table:
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| Email | varchar(128) | NO | | NULL | |
+-------+--------------+------+-----+---------+----------------+
settings table:
+---------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| setting_value | tinyint(1) | NO | | NULL | |
+---------------+------------+------+-----+---------+----------------+
setting_user pivot table:
+------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+-------+
| setting_id | int(11) | NO | | NULL | |
| user_id | int(11) | NO | | NULL | |
+------------+---------+------+-----+---------+-------+
Where setting_user is the pivot table.
One more thing is considered when creating schema, that, will there be always three settings, or will there be more in future, when application is expanded!

database: best practice countries, country codes, country phone codes

I am looking for a "best practice" if you store country codes in a database but couldn't find a "this is the right way" for that. I want to store the 2 chars country code and also the country phone codes (eg Germany would be "DE" and "+49").
Actually my plan is as follows: create one table countriesand one table with country_codes. Something like this:
TABLE: countries
id INT(11)
code CHAR(2)
TABLE: country_codes
id INT(11)
country_id INT(11) FORGEIGN KEY (countries -> id)
phone_code VARHAR(6)
I think I need to split them because some countries have more than one phone code. This way a country can have multiple phone codes.
But to my question: is that the "best practice" to do that? No only from that point "that will work" also more from that view if I want to rollout my application in "all" countries or if I want to translate the app in multiple languages (in that case I wanted to use the countries table also for the different languages.
What is your way to do thing like taht, if you want to able to translate your app in any language without the need of re-coding stuff and if you also need a list of all countries in you app?
If it should matter: I am planing to go with laravel for this app.
Country codes are standardized to two letters by ISO 3166-1-alpha-2, so storing them that way will work. It's often helpful to include a country name in the table, so a user can choose the right country without having to know all the codes.
Telephone numbers are far less standardized. The ITU offers recommendation E.164 for representing actual telephone numbers (called "directory numbers" in telephony jargon). Country codes are defined as one to three digits. North America (including USA, Canada and many Carribean nations) all are part of the North American Numbering Plan and share the country code 1.
Directory numbers are typically preceded by + and punctuated by dots. So, for example, the published New York City directory assistance number is (or was when they still had such a service) +1.212.555.1212. If you called that number from someplace in Europe, you would see the + and substitute your local international prefix. In NANP, multiple nationalities have the same country code.
But, UK is strange. Calling from outside the country, it's +44.exchange.number. But calling long distance from within the country it's (0) exchange.number.
My point: it's hard to get it right if you try to compose directory numbers with a country code in your software. You're probably better off asking users to provide their telephone numbers with the international prefix.
You should definitely not tie E.164 country codes to ISO 3166 two-letter country codes by putting them as different columns on the same row of a table. You need two separate tables to be future proof. The standardization organizations are different and do their own things, so your data model should reflect that.
Read this: Falsehoods Programmers Believe About Telephone Numbers.
My DB looks like this:
> id int(11) Auto Increment (Just an ID (primary key))
> iso char(2) (2-letters ISO code)
> name varchar(80) (normalized name (all uppercase))
> nicename varchar(80) (Nicely formatted name)
> iso3 char(3) NULL (3-letters ISO code)
> numcode smallint(6) NULL (numeric ISO code)
> phonecode int(5) (phone code like '1' for USA, without '+')
It should be more then enough. You get user's phone number, remove zeroes at the beginning, remove any non-numerical characters, add a country code from DB and you are good to go!
Example:
1) User input (045) 111-22-33, Germany
2) You convert it to 451112233
3) Add code of Germany (49) from DB. You get 49451112233. Add '+' if you wish.
4) Now you can make a call or send SMS with Twilio or any other service.
If you want to "easily" translate the site to other languages, store all of your text in database and pull the right version depending on user's language preferences.
Based on the answers I would do the following:
DB Tables:
+------------------------------------------------------------+
| Table: countries |
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| iso_code2 | char(2) | NO | | NULL | |
| iso_code3 | char(3) | NO | | NULL | |
| num_code | int(3) | NO | | NULL | |
| name | varchar(48) | NO | | NULL | |
| nicename | varchar(48) | NO | | NULL | |
+--------------+--------------+------+-----+---------+-------+
// will store all countries available
+------------------------------------------------------------+
| Table: country_phonecodes |
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| country_id | int(11) | NO | | NULL | |
| phonce_code | int(6) | NO | | NULL | |
+--------------+--------------+------+-----+---------+-------+
// based on this page: https://countrycode.org/ there are
// countries with more than one code
// and also codes can be 6 chars long
+------------------------------------------------------------+
| Table: languages |
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| code | char(2) | NO | | NULL | |
| locale | char(5) | NO | | NULL | |
| name | varchar(50) | NO | | NULL | |
| native_name | varchar(50) | NO | | NULL | |
| flag | varchar(10) | NO | | NULL | |
+--------------+--------------+------+-----+---------+-------+
// table for available translations of the app
+------------------------------------------------------------+
| Table: country_languages |
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| country_id | int(11) | NO | | NULL | |
| language_id | int(11) | NO | | NULL | |
+--------------+--------------+------+-----+---------+-------+
// table for language suggestions for a given country
And some example inserts:
+---------------------------------------------------------------------------------------+
| Inserts: countries |
+-----+------------+------------+-----------+---------------------+---------------------+
| id | iso_code2 | iso_code3 | num_code | name | nicename |
+-----+------------+------------+-----------+---------------------+---------------------+
| 1 | de | deu | 276 | GERMANY | Germany |
| 2 | do | dom | 214 | DOMINICAN REPUBLIC | Dominican Republic |
| 3 | be | bel | 056 | BELGIUM | Belgium |
+-----+------------+------------+-----------+---------------------+---------------------+
+----------------------------------+
| Inserts: country_phonecodes |
+-----+-------------+--------------+
| id | country_id | phonce_code |
+-----+-------------+--------------+
| 1 | 1 | 49 |
| 2 | 2 | 1809 |
| 3 | 2 | 1829 |
| 4 | 2 | 1849 |
| 5 | 3 | 32 |
+-----+-------------+--------------+
+----------------------------------------------------------+
| Inserts: languages |
+-----+-------+---------+---------+--------------+---------+
| id | code | locale | name | native_name | flag |
+-----+-------+---------+---------+--------------+---------+
| 1 | de | de_DE | German | Deutsch | de.svg |
| 2 | do | es_DO | Spanish | Español | es.png |
| 3 | be | fr_BE | French | Français | fr.jpg |
| 4 | be | nl_BE | Dutch | Nederlands | nl.png |
| 5 | be | de_BE | German | Deutsch | de.svg |
+-----+-------+---------+---------+--------------+---------+
+----------------------------------+
| Inserts: country_languages |
+-----+-------------+--------------+
| id | country_id | language_id |
+-----+-------------+--------------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 3 | 4 |
| 5 | 3 | 5 |
+-----+-------------+--------------+
I think this should work and be useable for any project where a country list and/or i18n is needed.
If a user comes from Belgium, he can choose from the list of available languages/translations. He will get a suggestion for FR, NL and DE but will still be able to choose es_DO as prefered language.
Think this should cover all needs - but if anyone sees a problem in that or has ideas/comments: I would be happy if I can improve this solution :)

Database structure for multiple locations of an organisation

I'm creating an application using PHP (Codeigniter/MySQL) and within the application are organisations.
Each organisation can have multiple locations, regions, departments, etc (I'm calling these areas)
Each area has an administrator, and sometimes I will need to escalate things to a higher area.
I've currently got all the data in 1 table, and I am using a parent_area_id and area_level to determine the parents,children etc.
But I think this is very inefficient, and I've been pointed towards closure loops, which I have no knowledge of.
Here the database table, is this ok, will it be efficient or is there a better way to do it?
+----------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+-------------+------+-----+---------+----------------+
| area_id | int(12) | NO | PRI | NULL | auto_increment |
| area_title | varchar(40) | NO | | NULL | |
| area_name | varchar(40) | NO | | NULL | |
| address1 | varchar(40) | YES | | NULL | |
| address2 | varchar(40) | YES | | NULL | |
| address3 | varchar(40) | YES | | NULL | |
| town | varchar(20) | YES | | NULL | |
| county | varchar(20) | YES | | NULL | |
| post_code | varchar(10) | YES | | NULL | |
| has_ra | varchar(1) | YES | | 0 | |
| org_id | int(12) | NO | MUL | NULL | |
| parent_area_id | int(8) | YES | | NULL | |
| area_level | int(1) | YES | | NULL | |
+----------------+-------------+------+-----+---------+----------------+
EDIT:
(better explanation of how this is being used)
1) Areas relate to customers of the business only.
2) The areas are different area(region,location,department) that a customer might have. (South region, Oxford Office, Accounts Dept).
3) Each area may have many employees allocated.
SO
If I had a regional administrator for example, they might have the following areas under them: e.g:
South Region
Oxford office
Sales Department
Accounts Department
London Office
Marketing
Planning
SO
If I wanted to get the user_id's of all employees under the regional administrator, using the above database structure, i would need to:
1) Query the db to get all area_id's that have a parent_area_id of the regional administrator.
2) Loop through each returned area_id, and query the db and get all area_id's that have a parent_area_id of the returned area_id
3) Continue looping through returned area_id's until we get to the bottom level
4) Query the db to get all user_id's that have an area_id of all above returned records
SO
That doesn't seem very efficient, and needs multiple SQL queries and programming loops to get a list of users associated with a regional manager.
If thats the most efficient way to do it then fine I just don't seem convinced, and im sure there must be an easier way?
There's no serious problem here if you're dealing with a situation where you're escalating one level at a time. I've got no idea how "closure loops" would factor in here, that's programming related, not a database schema concern, and is largely a matter of personal preference.
So long as you don't violate the Zero, One or Infinity Rule of design, you should be okay. Your multiple address fields here skirt the line, that might be better represented as a single field that accepts multiple lines of text, but that is also how a lot of databases traditionally represent arbitrary street addresses.

json data in mysql

I have a mysql table called "Data",
+---------+------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+-------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| data | text | YES | | NULL | |
| created | timestamp | NO | MUL | CURRENT_TIMESTAMP | |
+---------+------------------+------+-----+-------------------+----------------+
The field "data" has values like this:
606 | {"first_name":"JOHN","last_name":"SLIFKO","address":"123 main AVE","city":"LAKEWOOD","state":"OH","zip":"20190","home_phone":2165216359,"email":"john#gmail.com",} | 2012-12-04 16:37:23 |
So, it is saving the records in a JSON Format from a PHP Script that I have.
THIS IS THE THING:
How can I structure this table to make faster searchs or consults by every single field like doing searches or queries like:
SELECT * FROM Data WHERE first_name = john;
how can I do this???
Help please......
Yikes. Not a good design. About the best you could do is use the like keyword
Select * from Data Where data like '%"first_name":"JOHN"%'

Complex sorting on MySQL database

I'm facing the following situation.
We've got an CMS with an entity with translations. These translations are stored in a different table with a one-to-many relationship. For example newsarticles and newsarticle_translations. The amount of available languages is dynamically determined by the same CMS.
When entering a new newsarticle the editor is required to enter at least one translation, which one of the available languages he chooses is up to him.
In the newsarticle overview in our CMS we would like to show a column with the (translated) article title, but since none of the languages are mandatory (one of them is mandatory but i don't know which one) i don't really know how to construct my mysql query to select a title for each newsarticle, regardless of the entered language.
And to make it all a little harder, our manager asked for the possibilty to also be able to sort on title, so fetching the translations in a separate query is ruled out as far as i know.
Anyone has an idea on how to solve this in the most efficient way?
Here are my table schema's it it might help
> desc news;
+-----------------+----------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+----------------+------+-----+-------------------+----------------+
| id | int(10) | NO | PRI | NULL | auto_increment |
| category_id | int(1) | YES | | NULL | |
| created | timestamp | NO | | CURRENT_TIMESTAMP | |
| user_id | int(10) | YES | | NULL | |
+-----------------+----------------+------+-----+-------------------+----------------+
> desc news_translations;
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| enabled | tinyint(1) | NO | | 0 | |
| news_id | int(1) unsigned | NO | | NULL | |
| title | varchar(255) | NO | | | |
| summary | text | YES | | NULL | |
| body | text | NO | | NULL | |
| language | varchar(2) | NO | | NULL | |
+-----------------+------------------+------+-----+---------+----------------+
PS: i've though about subqueries and coalesce() solutions but those seem rather dirty tricks, wondering if something better is know that i'm not thinking of?
This is not a fast approach, but I think it gives you what you want.
Let me know how it works, and we can work on speed next :)
select nt.title
from news n
join news_translations nt on(n.id = nt.news_id)
where nt.title is not null
and nt.language = (
select max(x.language)
from news_translations x
where x.title is not null
and x.new_id = nt.news_id)
order
by nt.title;
Assuming I've read your problem aright, you want to get a list of titles for articles, preferring the "required" language? A query for that might go along the lines of ...
SELECT * FROM (
SELECT nt.`title`, nt.news_id
FROM news n
INNER JOIN news_translations nt ON (n.id = nt.news_id)
WHERE title != ''
ORDER BY
CASE
WHEN nt.language = 'en' THEN 3
WHEN nt.language = 'jp' THEN 2
WHEN nt.language = 'de' THEN 1
ELSE 0 END DESC
) AS t1
GROUP BY `news_id`
This example prefers a title in English (en) if available, Japanese (jp) as a second preference, and German (de) as a third, but will display the first 'other' entry if none of the requested languages are available.

Categories