MySQL - Similar headings - multiple tables - mysql

I have 2 tables, one containing the main information with a second table containing the same fields plus additional. The second table would have data which should overwrite the first table when queried. The fields are bigger, I've just shortened them down to show here.
First table (products):
+----+--------------+--------------+---------------+--------------------------+
| id | manufacturer | product_name | product_title | product_description |
+----+--------------+--------------+---------------+--------------------------+
| 1 | testingA | productA | productTitleA | main product description |
| 2 | testingA | productB | productTitleB | main product description |
| 3 | testingA | productC | productTitleC | main product description |
+----+--------------+--------------+---------------+--------------------------+
Second Table (products_secondary)
+----+------------+--------------+--------------+---------------+----------------------+---------+
| id | product_id | manufacturer | product_name | product_title | product_description | context |
+----+------------+--------------+--------------+---------------+----------------------+---------+
| 1 | 1 | (null) | (null) | (null) | new description here | test |
+----+------------+--------------+--------------+---------------+----------------------+---------+
My aim is to select the values from the second table where context = text
Expected result:
+----+--------------+--------------+---------------+--------------------------+
| id | manufacturer | product_name | product_title | product_description |
+----+--------------+--------------+---------------+--------------------------+
| 1 | testingA | productA | productTitleA | new description here |
| 2 | testingA | productB | productTitleB | main product description |
| 3 | testingA | productC | productTitleC | main product description |
+----+--------------+--------------+---------------+--------------------------+
The query which I know works is the following:
SELECT IFNULL(`products_secondary`.`product_description` , `products`.`product_description`) AS `product_description`
FROM `products`
LEFT JOIN `products_secondary` ON `products_secondary`.`product_id` = `products`.`id` AND `products_secondary`.`context` = 'test'
I'm sure there is an easier way to do this than having to supply IFNULL() for each field. Here is an SQL Fiddle: http://sqlfiddle.com/#!9/6985b/1
Thanks.

Use this query
SELECT a.id, a.manufacturer, a.product_name, a.product_title, IF(b.context IS NOT NULL, b.product_description, a.product_description) as product_description
FROM
products a
LEFT OUTER JOIN products_secondary b ON a.id=b.product_id

Related

MySQL join query only one row with reference table

Here is my 5 tables.
product
id(PK)
name
description
id(PK)
body
price
id(PK)
currency
product_description
id(PK)
product_id
description_id
product_price
id(PK)
product_id
price_id
Table product, description, price is where stored actual data.
And table product_description and product_price is reference table.
My expected query result like this.
product_id | product_name | description_body | price_currency
Current table's data
product
+----+----------------+
| id | name |
+----+----------------+
| 1 | first product |
| 2 | second product |
| 3 | third product |
+----+----------------+
description
+----+------------+
| id | body |
+----+------------+
| 1 | first desc |
| 2 | second des |
| 3 | third desc |
+----+------------+
price
+----+-------------+
| id | currency |
+----+-------------+
| 1 | first cur |
| 2 | second cur2 |
| 3 | third cur |
+----+-------------+
product_description
+----+------------+----------------+
| id | product_id | description_id |
+----+------------+----------------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
+----+------------+----------------+
product_price
+----+------------+----------+
| id | product_id | price_id |
+----+------------+----------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
+----+------------+----------+
Query
SELECT product.*, description.body, price.currency FROM product
LEFT JOIN product_description ON product.id = product_description.product_id
LEFT JOIN product_price ON product.id = product_price.product_id
LEFT JOIN description ON description.id = product_description.description_id
LEFT JOIN price ON price.id = product_price.price_id
Result
+----+----------------+------------+-------------+
| id | name | body | currency |
+----+----------------+------------+-------------+
| 1 | first product | first desc | first cur |
| 2 | second product | second desc| second cur2 |
| 3 | third product | third desc | third cur |
+----+----------------+------------+-------------+
In that moment, If I insert into product_description one more row that has product_id=1 and re querying, it shows many rows that product_id=2.
After insert into product_description values(4, 2, 1)
product_description
+----+------------+----------------+
| id | product_id | description_id |
+----+------------+----------------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 2 | 1 |
+----+------------+----------------+
After join query.
+----+----------------+------------+-------------+
| id | name | body | currency |
+----+----------------+------------+-------------+
| 1 | first product | first desc | first cur |
| 2 | second product | second desc | second cur2 |
| 2 | second product | first desc | second cur2 |
| 3 | third product | third desc | third cur |
+----+----------------+------------+-------------+
You know that because of product=2 row's count is 2 in product_description, result print all of it.
But I want to only last one rows that contain product=2.
Maybe limit or distinct is useful, I don't know it is possible.
Can I use limit or distinct in join query?
You can try using correlated subquery
SELECT product.*, description.body, price.currency FROM product
LEFT JOIN
( select * from product_description
where product_description.id in (select max(id) from product_description b
where product_description.product_id=b.product_id)
) as x ON product.id = x.product_id
LEFT JOIN product_price ON product.id = product_price.product_id
LEFT JOIN description ON description.id = x.description_id
LEFT JOIN price ON price.id = product_price.price_id

How to perform full text search in MySQL joining multiple tables

I'm creating e-commerce web site using MySQL. I have successfully created and inserted data to database.
Here is my database schema
table: categories table: product_types
+----+--------------+ +----+-------------+------------+
| id | name | | id | category_id | name |
+----+--------------+ +----+-------------+------------+
| 1 | Electronics | | 1 | 1 | Smartphone |
| 2 | Fashion | | 2 | 1 | Speakers |
+----+--------------+ +----+-------------+------------+
table: products
+----+-----------------+-------------+-------------------+-------+
| id | product_type_id | category_id | name | price |
+----+-----------------+-------------+-------------------+-------+
| 1 | 1 | 1 | Samsung Galaxy A3 | 300 |
| 2 | 1 | 1 | Samsung Galaxy A7 | 400 |
+----+-----------------+-------------+-------------------+-------+
table: options table: option_values
+----+-----------------+-------+ +----+-----------+------------+
| id | product_type_id | name | | id | option_id | name |
+----+-----------------+-------+ +----+-----------+------------+
| 1 | 1 | RAM | | 1 | 1 | 512 MB |
| 2 | 1 | Screen| | 2 | 1 | 1 GB |
| 3 | 1 | OS | | 3 | 3 | Android 5 |
+----+-----------------+-------+ | 4 | 3 | Android 6 |
| 5 | 2 | HD |
| 6 | 2 | FHD |
+----+-----------+------------+
table: product_option_values
+----+------------+-----------+-----------------+
| id | product_id | option_id | option_value_id |
+----+------------+-----------+-----------------+
| 15 | 1 | 1 | 1 |
| 16 | 1 | 2 | 5 |
| 17 | 1 | 3 | 3 |
| 18 | 2 | 1 | 2 |
| 19 | 2 | 2 | 6 |
| 20 | 2 | 3 | 4 |
+----+------------+-----------+-----------------+
Search must trigger through name column of each table and return name and price from products table.
The problem is that I don't know how to perform full text search joining all that tables.
Is there any easy way to do it?
You need a query that LEFT JOINs on each table to search with a condition based on fulltext search function MATCH, with a WHERE clause to filter out non-matching records. The SELECT DISTINCT ensures that you will not see duplicates.
We need to adjust manually the JOIN criteria from each table to products : option_values is the most complicated case as it does not directly references products (an additional join on product_option_values is needed, aliased pov below.
SELECT DISTINCT p.name, p.price
FROM
products p
LEFT JOIN categories c
ON MATCH(c.name) AGAINST('foo' IN NATURAL LANGUAGE MODE)
AND c.id = p.category_id
LEFT JOIN product_types pt
ON MATCH(pt.name) AGAINST('foo' IN NATURAL LANGUAGE MODE)
AND pt.category_id = p.category_id
LEFT JOIN options o
ON MATCH(o.name) AGAINST('foo' IN NATURAL LANGUAGE MODE)
AND o.product_type_id = p.product_type_id
LEFT JOIN product_option_values pov
ON pov.product_id = p.id
LEFT JOIN option_values ov
ON MATCH(ov.name) AGAINST('foo' IN NATURAL LANGUAGE MODE)
AND ov.id = pov.option_value_id
WHERE
COALESCE(c.id, pt.id, o.id, ov.id) IS NOT NULL

MYSQL Join returns duplicate column name

I am new to SQL and have the following challenge, I have a table on the left that has products assigned to a single company and denoted by a ref_id (it comes from another table, and I have simplified it for sake of question) and I have a master list. I want to compare all the products for company "A" against the master list and show all the products company A has not subscribed to. I am using JOIN and end up getting duplicate column names which throws my PHP program off. Here is what I have tried several syntax for UNION, RIGHT JOIN, LEFT JOIN and NOT operators, and the below is the closest I have gotten, however I am getting duplicate column names and I only need the last table with the last 2 columns. Please advise.
mysql> select ref_id, product_id, short_name from ap_company_product order by ref_id, product_id;
+--------+------------+------------+
| ref_id | product_id | short_name |
+--------+------------+------------+
|      2 | 10         | product 10 |
|      2 | 11         | product 11 |
|      2 | 12         | product 12 |
|      2 | 15         | product 15 |
|      2 | 17         | product 17 |
|      2 | 21         | product 21 |
|      3 | 11         | product 11 |
|      3 | 13         | product 13 |
|      3 | 17         | product 17 |
|      3 | 20         | product 20 |
+--------+------------+------------+
10 rows in set (0.00 sec)
THE MAIN LIST
mysql> select  product_id, short_name from ap_company_product_list;
+------------+-------------+
| product_id | short_name  |
+------------+-------------+
| 10         | product 10  |
| 11         | product 11  |
| 12         | product 12  |
| 13         | product 13  |
| 14         | product 14  |
| 15         | product 15  |
| 16         | product 16  |
| 17         | product 17  |
| 18         | product 18  |
| 19         | product 19  |
| 20         | product 20  |
| 21         | product 21  |
| 22         | product 22  |
+------------+-------------+
13 rows in set (0.00 sec)
Another SQL which is the actual results I need
SELECT aa.product_id as product_id, aa.short_name as short_name, aa.ref_id as ref_id, bb.product_id as product_id, bb.short_name as short_name FROM (select ref_id, product_id, short_name from ap_company_product where ref_id=2) aa RIGHT OUTER JOIN ap_company_product_list bb ON aa.product_id = bb.product_id where aa.product_id is NULL;
+------------+------------+--------+------------+------------+
| product_id | short_name | ref_id | product_id | short_name |
+------------+------------+--------+------------+------------+
| NULL       | NULL       |   NULL | 13         | product 13 |
| NULL       | NULL       |   NULL | 14         | product 14 |
| NULL       | NULL       |   NULL | 16         | product 16 |
| NULL       | NULL       |   NULL | 18         | product 18 |
| NULL       | NULL       |   NULL | 19         | product 19 |
| NULL       | NULL       |   NULL | 20         | product 20 |
| NULL       | NULL       |   NULL | 22         | product 22 |
+------------+------------+--------+------------+------------+
7 rows in set (0.01 sec)
Just use this:
SELECT bb.product_id as product_id, bb.short_name as short_name FROM (select ref_id, product_id, short_name from ap_company_product where ref_id=2) aa RIGHT OUTER JOIN ap_company_product_list bb ON aa.product_id = bb.product_id where aa.product_id is NULL;
BTW, I would prefer this one:
SELECT product_id, short_name FROM ap_company_product_list WHERE product_id NOT IN (SELECT product_id FROM ap_company_product);

MySQL function: rank table by most similar attributes

I have a table of products ids and keywords that looks like the following:
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| product_id | int(10) unsigned | YES | MUL | NULL | |
| keyword | varchar(255) | YES | | NULL | |
+------------+------------------+------+-----+---------+----------------+
This table simply stores product ids, and keywords associated with those products. So for example, it might contain:
+----+------------+---------+
| id | product_id | name |
+----+------------+---------+
| 1 | 1 | soft |
| 2 | 1 | red |
| 3 | 1 | leather |
| 4 | 2 | cloth |
| 5 | 2 | red |
| 6 | 2 | new |
| 7 | 3 | soft |
| 8 | 3 | red |
| 9 | 4 | blue |
+----+------------+---------+
In other words:
product 1 is soft, red, and leather.
product 2 is cloth, red and new.
Product 3 is red and soft,
product 4 is blue.
I need some way to take in a product ID, and get back a sorted list of product ids ranked by the number of common keywords
So for example, if I pass in product_id 1, I'd expect to get back:
+----+-------+------------+
| product_id | matches |
+------------+------------+
| 3 | 2 | (product 3 has two common keywords with product 1)
| 2 | 1 | (product 2 has one common keyword with product 1)
| 4 | 0 | (product 4 has no common keywords with product 1)
+------------+------------+
One option uses a self right outer join with conditional aggregation to count the number of matched names between, e.g. product ID 1, and all other product IDs:
SELECT t2.product_id,
SUM(CASE WHEN t1.name IS NOT NULL THEN 1 ELSE 0 END) AS matches
FROM yourTable t1
RIGHT JOIN yourTable t2
ON t1.name = t2.name AND
t1.product_id = 1
WHERE t2.product_id <> 1
GROUP BY t2.product_id
ORDER BY t2.product_id
Follow the link below for a running demo:
SQLFiddle
You need to use an outer join against the keywords for productid 1:
select y.productid, count(y2.keyword)
from yourtable y
left join (
select keyword from yourtable y2 where y2.productid = 1
) y2 on y.keyword = y2.keyword
where y.productid <> 1
group by y.productid
order by 2 desc
SQL Fiddle Demo
Results:
| productid | count(y2.keyword) |
|-----------|-------------------|
| 3 | 2 |
| 2 | 1 |
| 4 | 0 |

MySQL xref tables

I need some help with xref tables for some reason I am drawing a blank.
I have the following 3 tables
+---------------------+
| Products |
+---------------------+
| id |
| stock_number |
| size |
| qty |
+---------------------+
+-------------+
| Category |
+-------------+
| id |
| name |
| description |
| img |
+-------------+
*xref table
+--------------+
| category_prod|
+--------------+
| cat_id |
| prod_id |
+--------------+
With that in mind say I have
Category: Apples with an ID of 1
Product: Granny Smith with an ID of 2
Product: Yellow Delicious with an ID of 5
So I would have in the xref table category_prod:
+--------+---------+
| cat_id | prod_id |
+--------+---------+
| 1 | 2 |
| 1 | 5 |
+--------+---------+
How would i go about writing a query to grab all the products info using the xref table to see what products go under what category.
So basically I would want my output to be All the products from category apples to be displayed with all the fields from that product
Join the tables:
SELECT p.* FROM Products p
LEFT JOIN categry_prod cp ON cp.prod_id=p.id
WHERE cp.cat_id=1;