mysql joining two same columns - mysql

I know title is a bit confusing but i dont know how to name it better.
I have tables like that:
products:
product_id | product_name | product_category1 | product_category2
categories
category_id | category_name
I want to select record which looks like that:
product_id | product_name | category_name | subcategory_name (where category is category1 and subcategory is category2)
So what i need is to join 2 columns where each column is the "category_name" column but category_name has to have id saved in product_category1 and subcategory_name has to have id saved in product_category2
I tried a lot of things, but i am really stuck. I cant even paste my concept because, currently, i dont have one.

You just need to join products and categories twice, using different aliases for the categories table in the two joins. Something like:
SELECT prd.product_id, prd.product_name,cat.category_name,subcat.category_name
FROM products AS prd
JOIN categories AS cat ON cat.category_id = prd.product_category1
JOIN categories AS subcat ON subcat.category_id = prd.product_category2

Related

MySQL count unique over multiple tables

I have two tables:
products product_eans
+--+-----------+ +----------+-------------+
|id|name | |product_id|ean |
+--+-----------+ +----------+-------------+
| 1|hello world| | 1|4053804303361|
+--+-----------+ +----------+-------------+
| 2|hello mars | | 1|4053804304788|
+--+-----------+ +----------+-------------+
| 2|4053804304825|
+----------+-------------+
I now want to count the (unique) products that has the string 4788 in their name or in one of their EANs. The result in the example would be 1 (one product has an EAN that contains the search string 4788)
I have managed this with
SELECT
COUNT(DISTINCT products.id) AS count
FROM
products
WHERE
products.name LIKE "%4788%" OR
(SELECT
GROUP_CONCAT(ean)
FROM
product_eans
WHERE
product_id = product.id) LIKE "%4788%"`
but it’s incredible slow with thousands of rows in both tables.
What is the most efficient way for a query like this?
Using "double-ended wildcards" is never going to be fast because you won't get use of indexing so the tables will be scanned. An inner join is probably the most efficient
SELECT COUNT(DISTINCT e.products_id)
FROM product_eans e
inner join products p on e.products_id = p.id
WHERE e.ean LIKE '%4788%'
OR p.name LIKE '%4788%'
but one other possibility is to avoid the OR in tha wheer clause by using a union query like this:
SELECT
COUNT(*)
FROM (
SELECT
product_id
FROM product_eans
WHERE ean LIKE '%4788%'
UNION
SELECT
id
FROM products
WHERE name LIKE '%4788%'
) d
After being inspired by Used_By_Already, I came across a simple idea:
SELECT
COUNT(DISTINCT products.id) AS count
FROM
products
WHERE
products.name LIKE "%4788%" OR
products.id in (SELECT product_id FROM product_eans WHERE ean "%4788%")
It's super fast now. So thanks to Used_By_Already.

MYSQL Join if available

I have two tables I want to join, products and campaign_products
The tables look like this.
TABLE product
id | name
TABLE campaign_products
id | fk_campaign | fk_product | note
and if it's of interest
TABLE campaign
id | name
In all cases I need all the products returned, and if there is a row in the campaign_products which matches then add the values of those columns in as well. (null otherwise).
Remembering that multiple products can be part of multiple campaigns.
Here is what I tried, and in this case it only returns products that have a reference in campaign_products or products that don't exist at all in campaign_products so if the product is in campaign_products for another campaign it won't show up in other campaigns that don't include that product.
SELECT
product.id productId,
product.name productName,
campaign_product.note
campaignProductNote
FROMproduct
LEFT JOIN campaign_products ON product.id = campaign_products.fk_product
WHERE campaign_products.fk_campaign = 2 OR campaign_products.fk_campaign IS NULL
"2" changes based on the campaign being looked up.
I can't think of a way to solve this problem, is there a simple solution I'm missing ?
All you need to do is move the condition in the WHERE clause into the ON clause like so:
SELECT
product.id productId,
product.name productName,
campaign_product.note
campaignProductNote
FROM product
LEFT JOIN campaign_products ON product.id = campaign_products.fk_product
AND (campaign_products.fk_campaign = 2 OR campaign_products.fk_campaign IS NULL)

many to many to many mysql query

I'm trying to create a database that is structured so that I can do ONE query and get all the data I need.
this is how I have it structured now:
Products Subcategory Category
------------- ------------- -------------
| id | name | | id | name | | id | name |
It makes sense to me to create two relational tables that ties the product to the subcategory, and the subcategory to the category (making it hierarchical):
prod_sub_relation sub_cat_relation
---------------------------- ---------------------------
| id | prod_id | subcat_id | | id | subcat_id | cat_id |
So the product can be in MULTIPLE subcategories, and the subcategory tells us what category the product is in.
With this structure, if I wanted to find all the products with a category_id, I'd have to query the sub_cat_relation table, then take that array and make another query for the prod_sub_relation table (and that's just messy).
My goal is to find all products, or all categories, or all subcategories with ONE id (whether it's product_id, category_id, or subcategory_id)
Is this possible? or am I doing something wrong here?
As already mentioned by #har07 you could use a simple JOIN on this one.
I am not exactly sure the other details of the structure of your tables but
I will show you based on what you have provided so far:
SELECT p.ID, p.Name, c.Name as CategoryName, s.Name as SubCategoryName
FROM Products P
INNER JOIN SubCategory S
ON P.subcat_id = S.subcat_id
INNER JOIN Category C
ON S.cat_id = C.cat_id
You could then use a WHERE clause to specify which product you want to display along with its category and subcategory
SELECT P.ID, P.Name, C.Name as CategoryName, S.Name as SubCategoryName
FROM Products P
INNER JOIN SubCategory S
ON P.subcat_id = S.subcat_id
INNER JOIN Category C
ON S.cat_id = C.cat_id
WHERE P.ID = valuehereforyourID
To get the Products and SubCategory for a given category ID you just change the WHERE clause, like:
WHERE C.cat_id = ValueForCategoryIDhere
To get the Products and Category for a given Subcategory ID you just change the WHERE clause, like:
WHERE S.subcat_id = ValueForSubCategoryIDhere
Put each products' categories in an array, serialize the array, and store that in the DB...

MySQL join and column names

Let's say that I have the following tables in my MySQL database:
TABLE Products
| id | some_column1 | some_column2 |
TABLE ProductProperties
| id | product_id | name |
Oversimplified, but sufficient. Now I want to get all products with properties. I do:
SELECT * FROM `Products` JOIN `ProductProperties` ON Products.id = ProductProperties.product_id
What do I get?
| id | some_column1 | some_column2 | id | product_id | name |
It's not cool, and I want to make it cool in one of the two ways:
1) To get the array of objects like in Product table, but extended by one more member, which would be the array of properties which matched JOIN. I've sort of figured out already that it's impossible?
2) To get the array like this (I'd still have to iterate over it in PHP to join all properties in one product into one object):
| product_id | some_column1 | some_column2 | property_id | product_id | name |
So I'd like to rename the column ProductProperties.id into ProductProperties.property_id. If I could remove ProductProperties.product_id from the output too, that would be ideal, but for now, I only want the way to rename one column in the output. Or to prefix it by table name. Or something like that.
Doable?
You should explicitly name the columns and not use *. Then, don't return redundant columns:
SELECT p.id as productid, p.some_column1, p.some_column2,
pp.id as ProductPropertiesId, pp.name
FROM `Products` p JOIN `ProductProperties` pp
ON p.id = pp.product_id
Also, table aliases make such a query more readable.
SELECT Products.id product_id,
Products.some_column1,
Products.some_column2,
ProductProperties.id property_id,
ProductProperties.name
FROM `Products`
JOIN `ProductProperties`
ON Products.id = ProductProperties.product_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