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
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 am working on a website which hold millions of records now (apologies cannot reveal which site) initially it had few hundred records so the query below was acceptable
Query: SELECT * FROM….WHERE category LIKE ‘%,3,%’;
But now it just kills the database as for each query it has to go through the entire 2Mil records with above query
Category table
ID NAME
1 Female
2 Fashion
3 Clothing
4 Accessories
5 Top
6 Dress
7 Earring
8 Short dress
9 Long dress
10 Male
Product table
ID…..Category….other bits
1 ,1,2,3,6,9, ……
2 ,1,2,4,7,
3 ,1,2,3,5,
4 ,10,2,3,4,
you have the picture as what is happening above. Now if I do FullText index on category row in product table it gives only 1 cardinality :(
How can I overcome this?
I have considered duplicating row with each category but the database is huge currently 2 GIG and with duplicates it will turn roughly 10 GIG… more like a problem then a solution
Keep in mind that storing numbers as strings takes about twice as many bytes per digit as storing numbers as integers. Plus all those commas.
So if you're concerned about space, it won't be as much expansion as you fear to store the data in a normalized fashion.
And it will allow you to write proper queries that take advantage of indexes. So if there is some expansion, you will have traded a little bit of storage space for a big improvement in speed.
Tip: if you're using InnoDB, the primary key doesn't cost any storage because the table itself is stored as the primary key index. You should define your normalized table with the category id first and then the product id second, if you need to optimize for searches by category.
CREATE TABLE CategoryProduct (
categoryid INT,
productid INT,
PRIMARY KEY (categoryid, productid)
);
See also my answer to Is storing a delimited list in a database column really that bad? for more disadvantages to using comma-separated lists.
I would consider a new table, say Product_Category (unimaginative I know) where each row contains a column for a Foreign Key (FK) relation to the Product.id and a column for the category.
The category column can probably be a TINYINT which would only require 1 byte to store while I guess the FK column would be the same as the Product.id column (probably INT - 4 bytes), you could then index both columns so you can either find out which categories a product belongs to as well as which products belong in a category. Also, this table wouldn't need to have a Primary Key (i.e. id), saving you an an extra 4 bytes.
(see MySQL Data Type Storage Requirements)
With this solution each row in this new database would take up about 5 bytes. Since each character in the sting takes up 1 byte (Assuming ASCII and latin1 encoding), you would be looking at an increase of 3 bytes (including comma) per category per product by removing Product.category and putting the items into Product_Category, however that's no where near as big a gain as duplicating entire product rows. However, there is the cost of changing your code (unless you're far better than I am at joins).
Does this help any?
One solution I've seen is to use three tables:
categories lists your categories
products lists your products, without any attached category information
category_map is a special table: each row links a product_id to a category_id
To look up products by category, you can then match rows in category_map against rows in products.
This is an imperfect example, but it gets the gist of it:
SELECT * FROM
(
SELECT * FROM category_map
WHERE category_id=1
) AS map
INNER JOIN products
ON products.id = map.product_id;
Table joins are a very powerful tool; you may want to spend some time reading up on them, if you're new to using them. Coding Horror has a visual explanation that skims over the details.
It would be a good idea to set up foreign key constraints or otherwise make sure that entries in category_map correspond to existing entries in products and categories.
I am trying to sort the information given to me by the API of an engineering journal. I have extracted the following information into a table:
ID (integer),
Journal Entry Name (Text),
Description (Text),
Page Length (integer),
Has Media (boolean)
Each "Journal Entry" has only one ID associated with it. Each ID also has other characteristics that are not returned by the API but that I want to use to sort. They are:
Category (Things like Econ, Math, Biology. Each ID can have more than one category)
Boolean values (Things like requiring special subscriptions)
I have created a second table in the following format:
ID (integer),
Category (text),
Boolean1 (bool),
Boolean2 (bool),
Boolean3 (bool)
Since each ID can have more than one category, when this occurs another row is added to this table. The idea being that any given row only has one ID and one category in it.
What I want to do is this:
Be able to find the top ten categories when it comes to
Highest Journal Entry (ID) count
Highest Total Page Length
Highest Journal Entry count where the "Has Media" boolean is true
Create a means of navigating like "pagination" where each page shows the nth results of the aforementioned top ten.
So if I chose to Highest Journal Entry count method, the first page would be show IDs, Names, and Descriptions of all the Journal entries in the category with the highest count.
My plan has been to create a new table where the numbers one through ten are in the first column, and then populate the second column with the top ten categories. Then I can use a process similar to pagination in which the nth page only shows the values with the corresponding category from the original value. However I can't seem to be able to make this top ten list/matrix, nor do I know if it there is a better way.
Unfortunately I am not a MySQL or PHP coder by trade, and have only gotten this far by lots and lots of googling. I have been completely unable to find any guides for a navigation method like the one I want. And since I don't know the proper terminology, I am just trying random google searches at this point.
Is this the best way to go about it? Or would it be better to create a third table of some sort? Is there perhaps an easier way to do this with something that can use the PHP and MySQL code I already wrote?
Not sure I really understand what you're going for here, but my best guess is that you probably want to combine your two initial tables and have category be a set rather than an individual term so you can have a single entry per unique ID.
Then you'd just need to write calls for each of your top ten finds as needed. Since each id can have an unknown number of categories I would start with a limit of 10 and then process the returns starting with the top match, grab its categories, if there are more than 10 grab the first 10, if there are less than 10 grab what there are, update the amount you're looking for (if there were 4 then you're now looking for 6), and move on to the next best match.
Maybe something like this:
categories = null;
$delimeter = ',';
$count = 1;
$top10 = array();
$result = mysql_query("
SELECT *
FROM table_name
ORDER BY page_length DESC
LIMIT 10");
while($row = mysql_fetch_array($result) && $count <=10)
{
$categories = $row['categories'];
$id = $row['id'];
$splitcontents = explode($delimeter, $catagories);
foreach($splitcontents as $category){
if (!in_array($catagory,$top10)){
$top10[$count] = array(
'category'=>$category,
'journal_id'=>$id
);
$count++;
}
}
}
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'm trying to create a web index. Every advertiser in my database will be able to appear on a few categories, so I've added a categorys column, and in that column I'll store the categories separated by "," so it will look like:
1,3,5
The problem is that I have no idea how I'm supposed to select all of the advertisers in a certain category, like: mysql_query("SELECT * FROM advertisers WHERE category = ??");
If categories is another database table, you shouldn't use a plain-text field like that. Create a "pivot table" for the purpose, something like advertisers_categories that links the two tables together. With setup, you could do a query like:
SELECT A.* FROM advertisers AS A
JOIN advertisers_categories AS AC ON AC.advertiser_id = A.id
WHERE AC.category_id = 12;
The schema of advertisers_categories would look something like this:
# advertisers_categories
# --> id INT
# --> advertiser_id INT
# --> category_id INT
You should design your database in another way. Take a look at Atomicity.
Short: You should not store your value in the form of 1,3,5.
I won't give you an answer because if you starting you use it this way now, you going to run into much more severe problems later. No offense :)
It's not possible having comma-separated values to do this strictly in an SQL query. You could return every row and have a PHP script which goes through each row, using explode($row,',') and then if(in_array($exploded_row,'CATEGORY')) to check for the existence of the category.
The more common solution is to restructure your database. You're thinking too two-dimensionally. You're looking for the Many to Many Data Model
advertisers
-----------
id
name
etc.
categories
----------
id
name
etc.
ad_cat
------
advertiser_id
category_id
So ad_cat will have at least one (usually more) entry per advertiser and at least one (usually more) entry per category, and every entry in ad_cat will link one advertiser to one category.
The SQL query then involves grabbing every line from ad_cat with the desired category_id(s) and searching for an advertiser whose id is in the resulting query's output.
Your implementation as-is will make it difficult and taxing on your server's resources to do what you want.
I'd recommend creating a table that relates advertisers to categories and then querying on that table given a category id value to obtain the advertisers that are in that category.
That is a very wrong way to define categories, because your array of values cannot be normalized.
Instead, define another table called CATEGORIES, and use a JOIN-table to match CATEGORIES with ADVERTIZERS.
Only then you will be able to properly select it.
Hope this helps!