Concat foreign key values from a self related table - mysql

I have a products database which has a multi-tier category structure. Products are assigned to a category. The category table looks like this:
id name parent_id
================================
1 Electronics NULL
2 AV 1
3 Speakers 2
4 Wireless 3
What I want to do is, as part of my SELECT statement for products, output a concatenated string of the category tree.
The product is always assigned to the last category, so for example, Product "500w Wireless Speakers" would be assigned to category_id 4 (based on the above).
The ouputted column should be Electronics-AV-Speakers-Wireless.
Is this possible to do? I have looked at GROUP_CONCAT() but I'm having trouble working out the correct syntax.

Join as many times as you need, and concat the names:
select concat(a.name, '-', b.name, '-', c.name, '-', d.name) name
from mytable a
join mytable b on a.id = b.parent_id
join mytable c on b.id = c.parent_id
join mytable d on c.id = d.parent_id;

Related

How to find all children from another table?

I have two tables
CATEGORY
id category parent_id
1 Electronic
2 Furniture
3 Phone 1
4 LCD 1
5 Watch 1
6 Desk 2
ORDER
id customer product category_id
1 John Smartphone 3
2 Marry Montior 4
3 King Wood-Desk 6
I want to find all of electronic result by child_id.
Like this..
SELECT product FROM order WHERE category_id = (category.id = 1)
RESULT
product
Smartphone
Monitor
Is there any expression like this in MySQL?
You can use a join for this. You also will need to encapsulate the order table name with backticks because order is reserved (alternatively you could rename that table to save yourself from encapsulating everytime).
SELECT product FROM `order` as o
join category as c
on o.category_id = c.id
WHERE c.parent_id = 1
The on tells the DB what to data to join on. The as creates an alias so the full table name doesn't need to be written out everytime. (The as also is optional, I find it easier to read, FROM `order` o would be the same)
An alternative approach could be using a sub-query:
SELECT product
FROM `order`
WHERE category_id in (SELECT id FROM CATEGORY where parent_id = 1)
You have to use INNER JOIN
SELECT order.product
FROM order
INNER JOIN category
ON order.category_id = category.id
WHERE category.parent_id = 1
The ON keyword shows what columns will be compare between these tables. When you make a JOIN you need to put the table name before the column name separated with "." because it is possible to exist a column with the same name in both tables.

mysql retrieving unique id from table with division

In a table like this
ID | Category | Value
1 Device Computer
1 Location 1st Floor
2 Device Phone
2 Type Voip
2 Location 1st Floor
3 Device Computer
3 Location 2nd Floor
How do I get the ID of the where device='computer' and location='1st Floor'? The query is created programmatically and there might be many of these criteria that specifies a single ID in a statement.
You can use the join query like this for your problem.
select a.ID from MYTABLE a, MYTABLE b where a.ID=b.ID and a.Category='Device'
and a.VALUE='Computer' and b.Category='Location' and b.VALUE='1st Floor';
If there is may catogories like this then you must split the table like below.
TABLES :
Category with columns (CATOGORY_ID, CATOGORY)
Value with columns (VALUE_ID, VALUE)
MYTABLE with columns (ID, CATOGORY_ID, VALUE_ID)
then you should use join query.
select Distinct a.id
from myTable a inner join myTable b
on a.Id = b.Id
Where a.value = 'Computer' And b.value = '1st Floor' and a.Category = 'Device' and b.Category = 'Location'
Demo here

how i do this sql trick

I have a table in database for categories and sub categories. Its internal structure is:
id int not null primary
name text
subcatfrom int
it contains some of rows for categories and its sub categories. I want "SELECT" sql command to fetch categories and grouping their sub categories after it for every root category as following for example :
-cat1
--subcat1
--subcat2
-cat2
--subcat1
--subcat2
is it possible ?
The original question wants the subcategories on separate rows. Here is one way:
select name
from ((select category as name, 1 as iscat, category as sortorder
from t
) union all
(select tsub.category as name 0 as iscat, t.category as sortorder
from t join
tsub on
on t.subcategory_id = s.category_id
)
) a
where not exists (select 1 from category c where c.subcategory_id = a.sortorder limit 1)
order by sortorder, iscat desc, name
What is this doing? The inner union all is bringing together all categories and subcategories. It is assigning what you want in the table as well as information for sorting. The overall ordering is by "parent" category name.
The where clause is limiting this data to categories that are not the subcategory of anything else -- the top level categories.
I am making the assumptions that-
1. you have just one level of parent child relationship. ie subcategory can't have further sub-category
2. For top level category, value of subcatfrom is 0
SELECT * FROM
(
SELECT NAME AS parent_category_name, '' AS child_category_name FROM categories WHERE subcatfrom = 0
UNION
SELECT b.NAME AS parent_category_name, a.NAME AS child_category_name FROM categories a JOIN categories b ON a.subcatfrom = b.id
) a ORDER BY a.parent_category_name, a.child_category_name;
That's very easy but with this structure
Table: category_id , name , parent_id
Sample Data
category_id name parent_id
1 A 0
2 B 0
3 C 1
4 D 1
This means A is a category which has 2 subcategories C and D. And parent_id 0 means it is a parent category
Now the sql is
SELECT lc.category_id,
lc.name,
rc.subcategories
FROM categories
LEFT JOIN (
SELECT
subcategory_id ,
GROUP_CONCAT(name) AS subcategories
FROM categories) AS rc
ON lc.category_id = rc.parent_id
This will give you the following result
category_id name subcategories
1 A C,D
2 B (null)

A Better way to optimize these MySQL queries

I have two MySQL tables:
attributes (attributeid, name)
productsattributes (productid, attributeid, displayvalue)
The required is for each attribute name called "Product Type" get all other attributes associated with this "Product Type". As an example — attributes table will look like:
attributeid name
1 A
2 B
3 Product Type
4 D
productsattributes table will look like:
productid attributeid displayvalue
1 3 FAN
1 1 Brown
1 2 Stand
2 3 FAN
2 4 D
3 3 CAR
3 4 imported
So the final result should be:
FAN (A,B, Product Type,D)
CAR (Product Type, imported)
Here is my try:
first I get all the "displayvalues" from productattributes:
SELECT DISTINCT displayvalue
FROM productsttributes
WHERE attributeid = 3;
then I loop through each "displayvalues" to find the other attributes:
SELECT a.name
FROM attributes a
INNER JOIN productsattributes pa
ON pa.attributeid = a.attributeid AND productid in (
SELECT productid
FROM productsttributes
WHERE dispalyvale = '$displayvalue')
ORDER BY a.name;
The problem is the productattributes table has about 7 million rows, so my script is taking forever .. of course I am not looking for 10 minutes solution but at least it will improve my queries a bit.
I would start with the following statements:
ALTER TABLE attributes ADD CONSTRAINT p_attributes PRIMARY KEY (attributeid);
ALTER TABLE productsattributes ADD CONSTRAINT p_productsattributes
PRIMARY KEY(productid, attributeid);
ANALYZE TABLE attributes, productsattributes;
This will make sure all important fields are indexed.
The query might look like this (also on SQL Fiddle):
SELECT trg.displayvalue,
group_concat(a.name ORDER BY trg.productid, a.attributeid)
FROM (
SELECT t.productid,t.displayvalue
FROM attributes a
JOIN productsattributes t USING (attributeid)
WHERE a.name = 'Product Type') AS trg
JOIN productsattributes p ON p.productid = trg.productid
JOIN attributes a ON a.attributeid = p.attributeid
GROUP BY trg.displayvalue
ORDER BY 1;
Please, kindly include the EXPLAIN output of your's and this queries into your question.
Try this ::
Select displayvalue, attribute_name
from
(Select
product_id from productsattributes pa inner join attributes_table at on (pa.attributeid=at.id) where at.name=?) as productList
inner join productsattributes pa2 on(pa2.product_id=productList.product_id)
inner join attributes_table at2 on (pa2.attributeid=at2.id)

Retrieve parent category name from table in MYSQL results

I have a MYSQL table called 'categories' from a project I inherited from someone else.
id parent_id name
1 NULL Travel
2 NULL Sleep
3 NULL Eat
4 NULL Bath
5 1 Prams
6 1 Travel Systems
7 2 Cots
8 3 High Chairs
The table is obviously a lot bigger than that, but you get the general idea. I have a MYSQL statement which brings together this table with other category, brand and product tables, but basically I want to list the parent category name from the above table with the sub-category in the statement. How do I do this?
My current statement is something like:
SELECT brands.name, products.name, categories.id, categories.name, brands.id,
FROM `products` , `brands` , `categories`
WHERE products.brand_id = brands.id
AND products.category_id = categories.id
AND brands.name = '$brand'
ORDER BY categories.name, products.name
How do I retrieve the parent category names in the results?
For example if the product is a Pram, how can I output "Travel". I could do seperate MYSQL statements in the loop but I want to avoid this. This is either a stupidly simple question (in which case I apologise for being brain dead) or a little more complicated! Thanks.
First you need to know the parent id of the current category and then get the name for that id, you could use a subquery in this way:
SELECT name FROM categories WHERE id = (SELECT pid FROM categories WHERE name = $brand)
EDIT: Since you need to get the category and subcategory names in the same row for a given subcategory id, try this:
SELECT sc.name AS subcategory, c.name AS category
FROM categories sc
LEFT JOIN categories c ON c.id = sc.parent
WHERE sc.id = $subcategory_id