I have been given a project where there are multiple categories stored in a row in a comma delimited list (e.g. 1,2,3). Then I have a categories table that has categories that looks like this:
ID ShowcaseCategory DisplayOrder
1 Member's Work 0
2 Eastern Resorts 1
3 WesternResorts 2
4 Products 4
5 Nordic Skiing 3
I want to be able to pull the ShowcaseCategory (from above) from the table based on more than one value in the comma delimited list. For example, if the category contained 1,5 I would get Member’s Work and Nordic Skiing.
I think I need to get it in an array, possibly explode it and be able to do some join on the ID to get the (literal) ShowcaseCategory. Or, is there an easier way to do this?
In the end I want to dynamically build a list of checkboxes of Categories so they can be updated.
All help is appreciated
One option uses find_in_set(). Assuming that parameter :categories_list holds the csv list of categories ids, you would go:
select ShowcaseCategory
from mytable
where find_in_set(id, :categories_list)
Related
I was wondering if mysql has a way to look at a column and only retrieve the results when it finds a unique column once. For example
if the table looks like this:
id name category
1 test Health
2 carl Health
3 bob Oscar
4 joe Technology
As you can see their are two rows that could have the same category. Is their a way to retrieve the result where the array will one only return the category once?
What I am trying to do is get all the categories in the database so I can loop through them later in the code and use them. For example if I wanted to created a menu, I would want the menu to list all the categories in the menu.
I know I can run
SELECT categories FROM dbname
but this returns duplicate rows where I only need the cateogry to return once. Is there a way to do this on the mysql side?
I assume I can just use php's array_unique();
but I feel like this adds more overhead, is this not something MYSQL can do on the backend?
group by worked perfectly #Fred-ii- please submit this as answer so I can get that approved for you. – DEVPROCB
As requested by the OP:
You can use GROUP BY col_of_choice in order to avoid duplicates be shown in the queried results.
Reference:
https://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html
By using database normalization, you would create another table with an unique id and the category name and by that link those two together, like
select * from mytable1
on mytable1.cat = mytable2.id
group by mytable1.cat
You can ofcourse also use group by without multiple tables, but for the structure, I recommend doing it.
You can use select distinct:
SELECT DISTINCT categories
FROM dbname ;
For various reasons, it is a good idea to have a separate reference table with one row per category. This helps in many ways:
Ensures that the category names are consistent ("Technology" versus "tech" for instance).
Gives a nice list of categories that are available.
Ensures that a category sticks around, even if no names currently reference it.
Allows for additional information about categories, such as the first time it appears, or a longer description.
This is recommended. However, if you still want to leave the category in place as it is, I would recommend an index on dbname(categories). The query should take advantage of the index.
SELECT id, name from dbname GROUP BY categoryname
Hope this will help.
You can even use distinct category.
I'm trying to insert diferent numebers (like "10 11 12") into a MySQL field (the numbers come from PHP), but when I do the query, the field only gets the first number.
For example, I do:
UPDATE profile SET subcategory = '10 11 12' WHERE userId = 1 LIMIT 1
And the DB just registers '10'.
Any way to do it?
This happen because you're updating a number, probably an integer, so mysql do the job just for the first number.
If you do this:
UPDATE profile SET subcategory = 10 WHERE userId = 1 LIMIT 1
UPDATE profile SET subcategory = 11 WHERE userId = 1 LIMIT 1
UPDATE profile SET subcategory = 12 WHERE userId = 1 LIMIT 1
You'll just update the category with the third value (12).
I suggest you a user belonging to multiple subcategories so you'll have to create another table. Eg: a table called subcategories with at least two fields: userId and subcategoryId. And then you could do something like this:
DELETE FROM subcategories WHERE userId=1
INSERT INTO subcategories (userId, subcategory) VALUES (1,10)
INSERT INTO subcategories (userId, subcategory) VALUES (1,11)
INSERT INTO subcategories (userId, subcategory) VALUES (1,12)
The first line (delete) is used just to update the user's subcategories, first you delete all older subcategories for the user and then you insert the new ones. In PHP you could use a foreach() to automatize the insertion of multiple values.
You could also have a non unique userId in the table profiles with an entry per user subcategory but it will complicate things.
I hope it could help you
From your problem I guess that the type of your subcategory is integer. What happens when you put string? It is converted. The converter convert it to first proper integer which is 10 space after 10 is considered as string.
What can solve your problem?
Chance db structure and depend on relations.
(bad idea) change the type to varchar for example and then insert will be done(DONT DO IT)
Do multiple updates(it really depends on db structure)
This very much depends on the problem you are trying to solve.
If you are just trying to store a small number of numbers then using the php join and split functions to take a list of numbers and convert to and from a string and store that in a VARCHAR.
A better way to solve the problem would be to understand the layout of your data. Try having a table that links profiles to subcategories. Two columns, one for the profile ID and one for the Subcategory ID. You might find having a search for database normalisation informative.
This presentation looks relatively informative: http://www.sqa.org.uk/e-learning/MDBS01CD/page_26.htm
Dear Stackoverflowers,
I have a mysql query which checks if some sub categories are part of a categoryID to show all products from subcategories in the main category.
For example:
Category
Subcategory 1
Subcategory 2
Subcategory 3
For example products are added to subcats but are ALL beeing shown in the head category.
This works fine and i do this with WHERE cID in (' . $subids . ')
But now comes it, the cID used to hold just one value but since it has to be possible to add products to multiple categories i now save the multiple selected ids as comma separated in the cID field.
So im searching for a way to basicly find a match from a comma seperated list within a comma separated list because cID has now become comma separated ID's and FIND_IN_SET does not work with this.
I hope someone can shine some light, thank you all!
Have a read of these:
Many-to-many data model
Junction table
Implementing this, as opposed to comma-separated values, should probably save you and your coworkers a lot of headache and simplify your queries, effectively eliminating the need of complex queries. It should be faster, too.
Add full-text search index on this column in the database and then use following sql query
Ref - http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
Storing a CSV in a single field is not a good idea. Searching on that requires use of LIKE clause.
where CID LIKE '$cid1,' or CID LIKE ',$cid1,' or CID LIKE ',$cid1' or
CID LIKE '$cid2,' or CID LIKE ',$cid2,' or CID LIKE ',$cid2' or
.... so on
Also FIND_IN_SET would work too.
where FIND_IN_SET( $cid1, CID ) OR FIND_IN_SET($cid2, CID) .. so on
i now save the multiple selected ids as comma separated in the cID field. That's a very bad approach ,why would you store a CSV in a single field ,you shud change your design ,make a seperate table where each value will have a new row and will be mapped to a FK.
What you really need to do,is work on your DB design,read on Normalization and other related topics,I have so added some links,
MSDN Link on Many to Many
Databae Normalization
I have a table with products that fall under specific categories, but the products within each category can contain multiple meta data tracking field
Table: products
id name category metadata
1 something 1 blue,red,purple
2 something else 2 left,right,middle
I have been trying to contemplate the best method to have a single product table but can't seem to squeeze the metadata in conveniently. for now I have created a table with all the metadata and fields for tracking the related category (the sequence is so i can order them withing a dropdown etc..)
Updated table: products
id name category metadata
1 something 1 1,2,3
2 something else 2 4,5,6
Table: metadata
id category sequence option
1 1 1 blue
2 1 2 red
3 1 3 purple
4 2 1 left
5 2 2 right
6 2 3 middle
If this format makes sense .. I am trying to generate a query that will search for values in my product table and grab each and all of the related meta values. The issue I am having is trying to find a unique value in the products field. if I do a MySQL search for LIKE(%1%) I will get matches for 1, 11, 21, 31 etc ... I thought of adding a leading and trailing comma to the field by default and then search for ",1," which would be unique .. but there has to be a better way ...
Any recommendations (regarding format or query)?
It's not an ideal design to have comma-separated values within a single database field. Aside from the problem you mentioned (difficult to search), your queries will be less efficient, as the DB won't be able to use indices for the lookup.
I'd recommend making a separate table products_metadata with a many-to-one relationship to the products table. Have the *metadata_id*, and the *product_id*, which is a foreign key linking back to the products table. That will make your job much easier.
You want to add another table, which links products to their metadata. It will have two columns: productid and metadataid which refer to the relevant entries in the products and metadata tables respectively. Then you no longer keep metadata in the products table, but JOIN them together as required.
I have been experimenting with RDB design lately, and I was wondering about storing items in a field that can have more than one value:
CARS Color_avail
1 corvette 1, 2, 3 <<<<<<<
2 ferrari 2
3 civic 1
COLORS
1 red
2 White
3 black
so on CRUD I would like to add more than one item via a drop down / checkboxes or something that would hold multiple values.
I can see the benefit of displaying the output like this in a form, but do you really want to store it like this in the database ?
For example with a datamodel that holds a comma separated list as in your example, what SQL would you use to identify all the cars available in white ?
The traditional way to hold a many to many relationship like this is to use an additional table e.g. you have a separate table that holds CAR_COLOUR with the following contents
CAR COLOUR
1 1
1 2
1 3
2 2
3 1
So now you can easily query things like, get a list of all cars and colours
SELECT CAR, COLOUR
FROM CARS CA,
COLOUR COL,
CAR_COLOUR CACOL
WHERE CA.CAR=CACOL.CAR
AND CACOL.COL=COL.COLOUR
OR if you just want the white cars, add the following to the WHERE clause
AND COL.COLOUR='White'
an index on the id fields and on both fields in CAR_COLOUR will mean you get great performance even if you have thousands of rows whereas putting them all in a comma separated list in a single field will mean you have to use substr or like which would prevent the use of indexes and mean as the amount of data grows, the performance will degrade rapidly.
Storing relations in the coma-separated list makes sense in some senses. You don't need commas though. There are 2 existing controls which can help you with that.
Displaying list of values with checkboxes in a form:
$form->addField('CheckboxList','corvette')->setValueList($array);
(you can populate array through $model->getRows() although I think it needs to be associative. You can probably join them with var_dump and foreach).
Your other options is to use a hidden field with selectable grid.
$field = $form->addField('line','selection');
$grid = $form->add('MVCGrid');
$grid->setModel('Colors',array('name'));
$grid->addSelectable($field);
$form->addSubmit();
To hide the actual field, you can either use "hidden" instead of "line" or use JavaScript to hide it:
$field->js(true)->hide();
or
$field->js(true)->closest('dl')->hide();
if you need to hide markup around the field too.