When you create a user table with a column indicating whether the user is active or inactive or perhaps a payment table with the various payment status viz. “Payment received”, “Payment pending”, “payment cancelled”
what datatype do you prefer for the status column, do you keep it ENUM so that you can store the status as strings or do you keep the datatype as tinyint/int and store numbers representing each number as a status?
For just two states, I always do a boolean (is_active could be true for active or false for inactive).
For multiple ones, it depends:
If I know beyond a shadow of a doubt that there will never ever ever be another option I may need to add, I’ll use ENUM and specify each one of my choices.
If I think I might one day need to add another option, I use an int (depending what exactly it is I may use a smaller or larger version of int) which is an ID for another table where I list all of them.
So, for your payment example, I’d have two tables like this:
= payments
- payment_id (int)
- payment_status_id (int)
- ... # rest of the values
= payment_statuses
- payment_status_id (int)
- name (varchar)
MySQL databases should be able to stand 100% on their own without the need for PHP intervention.
Yes, you will have to do some joins, but with properly set foreign keys (in this case, payments.payment_status_id = payment_statuses.payment_status_id) and indexes (if they’re set up as keys they’ll automatically be indexed) the time to do the join is virtually zero until you’re joining thousands or millions of rows in one query.
The other problem with constants is they are constant, which is something you don’t always want. Sometimes you need to be able to declare new things on the fly (in this scenario, probably not, but others you may). If the list is truly constant and would never change, I would use enum (or boolean). The two tables is only for scenarios where the possible states are not constant.
Another question. Suppose you need to fetch all records from the payments table where the payment_status column is “Payment Completed”, how would you fire the query with following php code?
<?php
$sql = "select * from payments WHERE payment_status=?????";
mysql_query($sql);
?>
There are two ways. The first way would be to simply know what the ID of that specific payment status was (that would be the most reliable, since it wouldn’t change even if you changed the name):
<?php
$complete_id = 1;
$sql = "SELECT * FROM payments WHERE payment_status_id = '$complete_id'";
?>
The second would be to do a join looking for the name.
SELECT * FROM payments p
LEFT JOIN payment_statuses s
ON p.payment_status_id = s.payment_status_id
WHERE s.name = "Payment Completed"
The LEFT JOIN llinks the two tables together based ON rows that share that value and then gets them for those that have “Payment Completed” in the name field.
I can’t really make that call because I don’t know what you’re making. However, if you’re fairly confident that they will never change and you will never need to add another, I’d make it an enum.
If you think there is a possibility that they may change, I would use the two table approach. I would also create the initial values with PHP so I have control over the ID of the important one(s), and then store those where I can reference them without having to do a join based on name.
I usually use CHAR(1) for statuses so they are not completely meaningless numbers but still 1-byte in length. So for example “Payment received”, “Payment pending”, “payment cancelled” will be R, P and C respectively. Then in the column comment I store an explanation of what each letter means, e.g. “payment Pending; payment Received; payment Cancelled” so that I don’t get confused when viewing the table directly.
I know r937’s method is the most ‘proper’ one but I’m not keen on having so many separate tables for every possible status column as there can get many of them.