I have a table that puts multiple values into a single value in MySQL, separated by linebreaks. Like this:
+------------+-------------+
| Company | Products |
| (VARCHAR) | (TEXT) |
+------------+-------------+
| Acme Corp | Medicine |
| | Food |
| | Phones |
+------------+-------------+
| Ajax Corp | TVs |
| | Phones |
| | Pianos |
+------------+-------------+
I can't do anything about the table structure. Now I need a query that will return this table:
+==========+
| Products |
+==========+
| Food |
+----------+
| Medicine |
+----------+
| Phones |
+----------+
| Pianos |
+----------+
| TVs |
+----------+
I prefer a pure MySQL approach, but a solution with PHP is also OK for me.
There are no handy ways to split a field with MySQL. (Check the comments in the MySQL documentation). So, the best method seems to obtain all the product records with a simple:
SELECT Products FROM YourTable
And after in you php code:
$products = array_merge($products, explode("\n", $record));
for each record.
This will work for 3 products maximum,for more it needs a bit of tinkering
CREATE TABLE t
(
company varchar(20),
products text
);
INSERT INTO t
VALUES
('Acme', 'Medicine,Food,Phones'),
('ajax', 'TVs,Phones,Pianos');
SELECT SUBSTRING_INDEX(Products,',',1) FROM t
UNION
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Products,','),',',2),',',-1) FROM t
UNION
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Products,','),',',3),',',-1) FROM t
WHERE SUBSTRING_INDEX(Products,',',1)<>''
AND SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Products,','),',',2),',',-1) <>''
AND SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Products,','),',',3),',',-1)<>''
Results
Medicine
TVs
Food
Phones
Pianos
Related
Suppose I a table like this:
Categories:
| cat_id | cat_name |
|--------|----------|
| 1 | tvs |
| 2 | phones |
| 3 | tablets |
And then I have:
Products:
| product_id | product_name | product_category |
|------------|-----------------|------------------|
| 1 | tv sony | 1 |
| 2 | tv samsung | 1 |
| 3 | phone htc | 2 |
| 4 | phone motorolla | 2 |
| 5 | tablet apple | 3 |
And someone goes into index.php where I get 10 random products from the DB. For creating the link I'd have to fetch the database again (to get the name of the category) and then I could do something like mysite.com/phones/4 (that would be the link to phone motorolla).
Of course 10 wouldn't be too hard on the server but it's still another fetch on the database.
The other option is to fetch for the category name during the product creation, and generate a link there, something like:
| product_id | product_name | product_category | product_link |
|------------|-----------------|------------------|--------------|
| 1 | tv sony | 1 | tvs/1 |
| 2 | tv samsung | 1 | tvs/2 |
| 3 | phone htc | 2 | phones/3 |
| 4 | phone motorolla | 2 | phones/4 |
| 5 | tablet apple | 3 | tablets/5 |
However the name of the category may change and so the link wouldn't work anymore. So what should I do? Is there another way to do this?
Alright Nick so in SQL you have something very powerful called JOIN. A join in SQL allows you to merge columns from different tables based on a key. Usually the key is a primary key or a foreign key.
In your case, it seems you have as primary keys : cat_id and product_id
And as foreign key you have : product_category
Based on your database schema, you can query your tables like this :
SELECT p.product_id, p.product_name, c.cat_name
FROM PRODUCTS p INNER JOIN CATEGORIES c
ON p.product_category = c.cat_id
With this query you retrieve your product_id, product_name and cat_name based with only one query for your database.
Here is more info about joins in SQL => https://www.w3schools.com/sql/sql_join.asp
Hope it will help you.
For an university project I need to do the following:
Let the user enter ingredients via HTML form, process it via PHP into my MySQL database. For Example:
The user enters EGG and QUANTITY and CALORIES.
Let the user make recipes out of these ingredients. So another form with recipename and ingredients.
Now my question is: How can I connect these tables in a proper manner? So that tablerecipe with recipename knows repiceid 1 consists of 3 eggs, 100g beef and 300g cheese?
I read about lookup tables, but I don't understand them. Any help would be appreciated.
My table structure looks like this so far:
If each recipe will have multiple ingredients, and each ingredient will belong to only one recipe, then you have a One-to-Many relationship. You should define your tables like this:
+----------------+ +------------------+
| recipes | | ingredients |
+----------------+ +------------------+
| recipe_id <----------------+ | ingredient_id |
| recipe_name | | | ingredient_name |
| | +----------------+ recipe_id |
| | | |
| | | |
| | | |
| | | |
| | | |
+----------------+ +------------------+
Notice how the ingredients table has a recipe_id that points to a recipe in the recipes table. When you want to query all the ingredients that belong to a recipe, you could query it like this:
SELECT
*
FROM
recipes r
INNER JOIN ingredients i WHERE i.recipe_id = r.recipe_id
However, this is probably not what you want because you might want to use an ingredient more than once. In this case, each ingredient can belong to more than one recipe and each recipe can have more than one ingredient. This is a Many-to-Many relationship. You should define your tables like this:
+----------------+ +------------------+
| recipes | | ingredients |
+----------------+ +------------------+
| recipe_id <---+ +--> ingredient_id |
| recipe_name | | | | ingredient_name |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
+----------------+ | | +------------------+
| |
| +--------------------+ |
| | recipe_ingredients | |
| +--------------------+ |
| | id | |
+--+ recipe_id | |
| ingredient_id +--+
| quantity |
| type |
| |
| |
| |
| |
+--------------------+
Notice the extra table. This is sometimes called a bridge table and it associates a recipe_id with an ingredient_id. In this way, more than one ingredient can be associated with a recipe, and more than one recipe can be associated with an ingredient. I also added two extra columns to the bridge table that adds more information to the relationship. I added a quantity which is the amount of that ingredient to use, and a type which can be used to define the type of measurement (i.e. cups, grams, teaspoons, etc). When you want to query all the ingredients that belong to a recipe in this case, you could query it like this:
SELECT
*
FROM
recipes r
INNER JOIN ingredients_recipes ir ON ir.recipe_id=r.recipe_id
INNER JOIN ingredients i ON i.ingredient_id=ir.ingredient_id
I have a table called facility.
Structure looks as follows:
id | name
---------
1 | Hotel
2 | Hospital
3 | medical shop
I have an other table which is taking data from the above table and keeping multiple values in one column. View looks like below:
id | facilities
---------------
1 | Hospital~~medical shop~~Hotel
2 | Hospital~~Hotel
3 | medical shop~~Hotel
If I want to join these two tables how does the query look like?
I tried this, but it didn't work:
select overview.facilities as facility
from overview join facility on facility.id=overview.facilities;
you can do this with a bit of hackery
select o.facilities as facility
from overview o
join facility f on find_in_set(f.facilities, replace(o.facilities, '~~', ','));
I would highly recommend you change the way you are storing data. currently it is considered un normalized and that quickly becomes a monster to deal with
you should change your table structure to look something more like this
+----------+--------------+
| facility |
+----------+--------------+
| id | name |
+----------+--------------+
| 1 | Hotel |
| 2 | Hospital |
| 3 | medical shop |
+----------+--------------+
+-----------+-------------+
| overview |
+-----------+-------------+
| id | facility_id |
+-----------+-------------+
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 3 |
| 7 | 1 |
+-----------+-------------+
Code Explanation:
basically you are wanting to find the matching facilities in the overview. one handy function MySQL has is FIND_IN_SET() that allows you to find an item in a comma separated string aka find_in_set(25, '11,23,25,26) would return true and that matching row would be returned... you are separating your facilities with the delimiter ~~ which wont work with find_in_set... so I used REPLACE() to change the ~~ to a comma and then used that in the JOIN condition. you can go from here in multiple ways.. for instance lets say you want the facility id's for the overview.. you just add in the select GROUP_CONCAT(f.id) and you have all of the id's... note if you do that you need to add a GROUP BY at the end of your query to tell it how you want the results grouped
I have these tables:
Table 'Data':
| Customer | Category | Brand | Market | A | B |
|==========|==========|=======|========|===|===|
| Bill | 5 | 4 |1 |2 |9 |
| Bill | 5 | 4 |1 |6 |15 |
| Bill | 5 | 4 |1 |1 |30 |
| Greg | 7 | 9 |3 |5 |1 |
| Amy | 9 | 2 |1 |1 |8 |
Table 'Customer':
| Cust | Mkt | SubMkt |
|======|=====|========|
| Bill | 1 | NY |
| Bill | 2 | Arizona|
| Bill | 3 | Cali |
| Greg | 1 | Ohio |
| Amy | 1 | Texas |
Table 'Sort':
| SubMarket | SortBy |
|===========|========|
| Cali | A |
| Ohio | B |
| Arizona | A |
| NY | A |
I need to select all from 'Data' ordered by a few different columns and then either A or B depending on what 2 other tables say.
SELECT *
FROM Data
ORDER BY Customer, Category, Brand, Market, (A or B)
Basically, Customer and Market in table Data links to Cust and Mkt in table Customer, and then SubMkt in table Customer links to SubMarket in table Sort. Then SortBy in table Sort would be the column I need to sort by in table Data. Hope that makes sense.
So, in the above example, all of the rows in Data containing both "Bill" for Customer and "1" for Market would be sorted by column A.
I started to write an array of objects in PHP and then I would sort the array based on an object property but this would actually require a huge overhaul on my existing code. I assume what I'm looking for can be done with a fairly straight forward query in MySQL but I don't know MySQL well enough to write that query. Any help would be appreciated!
Edit: I should have mentioned, these are just partial tables. The actual tables I'm working with are thousands of rows and every "SubMarket" does have a matching "SortBy".
Edit 2: Clarified that Customer and Market is needed in table Data to link to Cust and Mkt in table Customer.
this is just an answer showing how to do the joins.. Ignacio should have the accepted answer as he provided the hard part first :)
SELECT d.*
FROM data d
JOIN customers c on c.cust = d.customer AND c.mkt = d.market
JOIN sort s on s.submarket = c.submkt
ORDER BY
d.Customer,
d.Category,
d.Brand,
d.Market,
CASE s.sortby
WHEN 'A' THEN d.A
WHEN 'B' THEN d.B
ELSE 9999999
END
You need a CASE expression.
CASE `Sort`.`SortBy`
WHEN "A" THEN `Data`.`A`
WHEN "B" THEN `Data`.`B`
ELSE NULL
END CASE
The ELSE NULL part is optional, but it can help reveal data problems.
I have 14 tables (one for every year) with product code, firm name and invoice numbers. Main structure of table is identical (product code, ID), but there can be some variables in names of firms.
Table2011
| ID | productcode | firm1 | firm2 | firm3 | etc |
| 1 | G-00001 | 2;5;40| 32;67 | | 150 |
| 2 | G-00005 | | 50 | | |
|etc | | | | | |
Table2010
| ID | productcode | firm1 | firm2 | firm3 |etc |
| 1 | G-00001 | 1;10 | | 55 | |
| 2 | G-00003 | | 2 | | |
| 3 | G-00005 | | 50 | 40 | |
| etc| | | | | |
Table2009
...
Column Firm1 do not usually equals to same firm as firm 1 in other table
I am using table editor to work with tables (adding columns to table, editing values…).
I would like to know if it is possible to achieve result like below. It is above my PHP skills.
Product G-00001 page
…
<UL>
<LI>Year 2011: 150etc; 67firm2; 40firm1; 32firm2; 5firm1; 2firm1</LI>
<LI>Year 2010: 55firm3; 10firm1; 1firm1</LI>
<LI>Year 2009: ...</LI>
...
</UL>
…
Lemme begin with book recommendation : SQL Antipatterns. You will need it, doesn't matter if you caused this mess or ar just assigned to fix it.
If i was in your place, first thing would do would be to fix the database structure. This is madness. You do not need a new table for each year and new column for each company. Database is not a form of Excel spreadsheet.
Invoices Years Companies
----------------- ------------- ---------------
| product_code PK | | year_id PK | | company_id PK |
| company_id FK | | number | | title |
| amount | ------------- ---------------
| year_id FK |
-----------------
Where PK - primary key and FK - foreign key.
This structure would make the gathering of information much much much MUCH easier.
If you just want to display the data and not worry about the restructuring just yet you can use a JOIN to display the information from all the tables.
Although I would agree with teresko you really need to redesign that database. It is not maintainable the way it is.