Forum Moderators: coopster

Message Too Old, No Replies

Convert number to text

Data extraction from MySQL database

         

max4

5:30 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



Hello,

I have a bunch of select menus that are designed in the following way:

[fixed]
<select>
<option value="1">Apples</option>
<option value="2">Bananas</option>
</select>
[/fixed]

The number '1' is what is being input into my MySQL database instead of the word 'Apples'. The difficulty arises in extracting the number value from the database and displaying it's fruit name. For example, a user is viewing another user's profile which lists favorite fruits. How do I get PHP to display 'Apples' instead of '1'? The only way I can think of would be a very long arduous process:

[fixed]
$selectedData = query used to extract from database
if ($selectedData == 1) {
echo 'Apples';
}
elseif ($selectedData == 2) {
echo 'Bananas';
} else {
echo '';
}
[/fixed]

For an example as simple as the one above, this would be fine; but I have option values ranging any where from 100 to just about 1200. 1200 if, elseif statements is quite the undertaking; there must be a better, more server friendly (and developer friendly) way of tackling this issue!

Also, I am currently setting the instances in the database tables (instances that store data similar to the above example) as INT rather than varchar since the input is only a number; is this wise?

Thank you.

mooger35

5:39 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



Sounds like an array would work for you

$array = array(1 => "Apples", 2 => "Bananas", 3 => "etc");

if(in_array($selectedData, $array)){
echo $array[$selectedData];
} else {
echo "Error msg";
}

Frank_Rizzo

5:47 pm on Jun 5, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You could have another lookup table

id, Fruit
1, Apple
2, Banana

then your select would join on id and get the fruit.

A quicker way would be to just store the fruit instead of the number in the database. It is a bit wasteful for database size but it would certainly speed up processing and coding time.

max4

5:49 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



Thank you mooger, this is exactly what I was looking for.

max4

5:53 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



Thanks Frank. I had already given much thought into that option; however, I have many, many select menus and if I went that way then I would also have many, many tables (with my current configuration).

Also, is it wise to store these number values in the database as INT or something else like varchar(4) for example?

mooger35

6:04 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



Personally I would go the table root and then populate the array with the table results. It would save you time down the road.

I like to use INT and then just use autoincrement for the ID.

[edited by: mooger35 at 7:00 pm (utc) on June 5, 2009]

idfer

6:15 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



The lookup table suggested by Frank_Rizzo is a pretty standard way of handling this type of data, and is best for maintainability. You could have a single lookup table with a "category" field:

category, id, label
fruit, 1, Apple
fruit, 2, Banana
veggie, 1, Carrot
veggie, 2, Cucumber

Make sure you define a unique index on category+id to make your queries efficient.

As far as INT vs VARCHAR, if the values are always numbers, it's definitely better to declare the field as INT, for one thing it's self-documenting. Also if you run queries like "SELECT * FROM table WHERE favorite_fruit = 1", an INT field with an index on it would be best for query optimization.

Then again, if you allow the user to specify several favorite fruits, a lazy way to implement that is to store the values as an imploded array, e.g. '1,3,4', so then you'd want to declare the field as VARCHAR and try to not include it in a WHERE clause, espcially as the only the condition (that would result in a full table scan).

max4

8:56 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



Thank you for the suggestions. A single look-up table would work, but for my configuration the array method would be better. There is already a reference hierarchy in my database table design and creating a single look-up table for all of my select options would create a mess of numbers indexing and referencing other tables. With mooger's array method, I can leave my database with it's current configuration and accomplish the same thing.

idfer, is there a non-lazy way of storing the values of multiple favorite fruits? I'm actually working on a multiple check box form right now and was planning on using the implode() function.

Gibble

9:08 pm on Jun 5, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I don't get why you have a database that stores values

eg 1 = apple and nowhere in your database do you have that 1 is an apple?

...what's the point of the DB if it's merely storing keys without that associated value?

max4

9:35 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



The point of a database is to provide a way for users to send information to a server, and then have the server store that information for as long as necessary and display it when the need arises. You don't necessarily need more information in the database to make sense of the information that is already there. Without a database, the information does not exist in any permanent manner (short of resorting to a text file).

If I can make sense of the data in my database without bogging it down then isn't that all that should matter?

Gibble

9:45 pm on Jun 5, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



But you end up hardcoding values in your pages rather than dynamically creating all your drop downs from the db.

It seems like a lot more work than necessary.

Like your predicament here, when you want to display information on another page, that 1 is meaningless without the associated value 'apple'

You're mixing your presentation layer with your data...storing data in your presentation layer just creates headaches.

max4

10:12 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



You make a good case, but I don't know any other way. I don't know how to populate select menus from the database.

idfer

10:26 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



idfer, is there a non-lazy way of storing the values of multiple favorite fruits?

You'd need to create a separate table for favorite_fruits, with a foreign key to your users table (there's a technical term for this relationship but i skipped that class in our DBMS course), so something like:

user_id, fruit_id
1, 1
1, 2
2, 1
3, 3

user_id is the foreign_key, you want to create a non-unique index on it, and maybe another index on fruit_id if you frequently need to lookup all users who like apples.

If I can make sense of the data in my database without bogging it down then isn't that all that should matter?

Having more data in your DB, especially in separate tables, doesn't bog it down at all. Keep in mind one of the top rules of software engineering is to implement with maintainability as a priority, and only optimize afterwards, if you find performance problems. Well, up to a certain point. Hope this helps.

I don't know how to populate select menus from the database.

Same principle as in mooger35's post, except you populate the array by selecting from the lookup table:

function getFruits() {
$fruits = array();
$qh = mysql_query('select * from fruits order by id');
if($qh === false) die mysql_error();
while($row = mysql_fetch_array($qh)) {
$fruits[$row['id']] = $fruits[$row['fruit']];
}
return $fruits;
}

max4

11:02 pm on Jun 5, 2009 (gmt 0)

10+ Year Member



Okay your function sold me. Also the fact that I learned CSS was to be able to create pages that validated but more importantly to separate design from presentation - which is why I could understand Gibbles argument for separating data from presentation.

Bear with me as this is uncharted territory. Currently my database is composed of a simple hierarchy of tables which reference other tables. So, we have a category table whose primary key ID is a number and the adjacent column is the name of that number.

categoryID ¦ category_name

Then we have a post table which references the category table.

postID ¦ columns... ¦ categoryID

And finally we have the individual category posts.

ID ¦ columns... ¦ postID

If I were to create a look-up table; then my post table and individual category tables would be composed primarily of foreign keys which all link back to the look-up table as well as to each other and back to the main category table. Am I understanding this correctly? Also, how can I keep track of segments in the look-up table? Like this segment (ID 1-4) is for fruits and that segment (ID 5-8) is for vegetables? Keep in mind we are looking at thousands of rows which will be inserted into this table.

idfer

12:40 am on Jun 6, 2009 (gmt 0)

10+ Year Member



Yes you're on the right track to have a nicely normalized database. For the single lookup table, you could add a separate column called optionType (or something more descriptive) and set it to "fruit" for all fruits, "veggi" for all vegetables, etc, then you don't have to worry about segments, and your query to select all fruits would become:

$qh = mysql_query("select * from lookupTable where optionType = 'fruit'");

To really normalize the DB, you could have a separate table (optionTypeID, optionType) for all optionTypes and use the optionTypeID in your lookup table, but that would be a bit of overkill. ;-)

Gibble

7:07 am on Jun 6, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



There are two ways you could separate your segments.

The first is have one table called fruits, and another called vegetables, and while it's descriptive, it can be difficult to maintain if you're going to have to keep adding new tables. Depending on the type, amount of data and the type of system this is sometimes the right decision, other times not.

In this case though, since your table definitions would be identical for both fruits and vegetables, with only their type being the difference, putting them in one table is the right decision. And since thousands of rows for a database to handle is literally nothing there's no need to split the table up into segments (I'm currently working with tables with over a billion records and they are still performing well).

One thing that will improve performance of your webpages though, is don't use "select * from...". Be specific in your select clause and only return the columns you use. The database doesn't much care, but the network certainly does, it'll speed up pages, and depending on the amount of traffic, it can significantly reduce bandwidth consumption.

To really normalize the DB, you could have a separate table (optionTypeID, optionType) for all optionTypes and use the optionTypeID in your lookup table, but that would be a bit of overkill. ;-)

As a 'trick' you can name the column optionTypeCode, and use 'fruit' or 'vegetable' as the code, and later if you need to store more information about the optionTypes in their own table, you would use it as a foreign key. So your new table table would contain optionTypeId, optionTypeCode, optionTypeDescription, etc, etc.

max4

4:22 pm on Jun 6, 2009 (gmt 0)

10+ Year Member



You know, I'm really glad I asked this question and, more importantly, that you two decided to comment. Before this I had to manually create select options and use Microsoft Excel to input all the values, and then again use Microsoft Excel to input all the case values in my switch validation system. Now it's as easy as creating a function and calling that function; boom, there is my switch statement and my select options.

I went with idfer's 'overkill' method since my database was already set up in a similar way. I have the look-up table properly indexed for quick and easy queries and for my while loops I simply add WHERE id = x;

Again, thanks a lot guys - I really appreciate you taking the time to comment and showing me that this kind of functionality exists in PHP.

I have one more question on this topic. So I created a while loop that looks like this:

[fixed]
$name_results = mysql_query("SELECT column, column FROM `table` WHERE column = 1");
if (statement) {
while($name_row = mysql_fetch_object($name_results)) {
Do stuff
}
} else {
No results
}
[/fixed]

Is it possible to have the while loop stop after let's say, the first 6 results so I can insert a bit of CSS deco? Basically something like this:

[fixed]
$name_results = mysql_query("SELECT column, column FROM `table` WHERE column = 1");
if (statement) {
while($name_row = mysql_fetch_object($name_results)) {
Do stuff but stop after 6 results
}
echo CSS deco
while($name_row = mysql_fetch_object($name_results)) {
Do stuff but start after last stop; stop after next 6
}
echo CSS deco
while($name_row = mysql_fetch_object($name_results)) {
Do stuff but start after last stop; show remaining options
}
} else {
No results
}
[/fixed]

idfer

6:11 pm on Jun 6, 2009 (gmt 0)

10+ Year Member



You're welcome max4. :-)

You want to use the modulus operator for that problem:

$name_results = mysql_query("..."); 
if (statement) {
$nrows = 0;
while($name_row = mysql_fetch_object($name_results)) {
Do stuff
$nrows++;
if($nrows % 6 == 0) {
echo CSS deco
}
}
} else {
No results
}

max4

7:48 pm on Jun 6, 2009 (gmt 0)

10+ Year Member



Hi, idfer. Thanks for the reply. Coming from a background of only CSS and HTML web languages I have never been in the position of using a variable in the way you used $nrows. I am starting to see how powerful this language really is.

The modulus operator checks for a remainder; so your code is saying every time we divide by 6 and a remainder of 0 is displayed then do the following. So every 6 rows, the same CSS design was being displayed. My goal was to display a different CSS design at the 12th row so I used the following instead:

[fixed]
if($nrows == 6)
if($nrows == 12)
[/fixed]

I really appreciate you siting the name of the operator rather than just showing code as it guided me in the right direction. Once again, I thank you for your input in this matter.

Gibble

8:00 pm on Jun 10, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You could also write it as


if($nrows % 12 == 0) {
// This should match 12, 24, 36, etc
} else if($nrows % 6 == 0) {
// This should match 6, 18, 30, etc
} else {
// All other rows
}

[edited by: Gibble at 8:01 pm (utc) on June 10, 2009]

max4

8:20 pm on Jun 10, 2009 (gmt 0)

10+ Year Member



Thanks Gibble, I appreciate the help and your original comment about my database methods. Since I've switched my job has become a lot easier. The intention with the operator was not to repeat the design but to fill in option groups between the various options. Though I can see many other instances where the modulus operator will come in handy.

Gibble

8:50 pm on Jun 10, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



No problem.

As a general rule in programing, if you ever find yourself repeating anything, you're doing it wrong.