MYSQL GROUP_CONCAT GOT AN ERROR IN MORE THAN 2 TABLES - mysql

Hi i need to fetch the product information from the backend ..
I have a
productTable
productInformation
productAttributes
productCategories
productImages
My database query is ,
select
p.id,
p.name as entityName,
pi.name,
pi.description,
pi.language,
GROUP_CONCAT(im.image SEPARATOR ';') as images,
ci.name as categoryname
from products p,
productInformation pi,
product_attributes pa,
images im,
categoryInformation ci,
categories c
where
ci.category=c.id and
ci.language='en' and
c.id = p.category and
p.category in (1,2) and
im.entityid=p.id and
im.type='product' and
pi.language='en' and
pi.productid=p.id and
pa.attributevalueid in (2) and
p.id=pa.productid and
p.name like '%p%' and
p.price between 0 and 15 ;
The query was working fine before ,
After i added the GROUP_CONCAT in the query
There is an error
ERROR 1140 (42000): In aggregated query without GROUP BY, expression
1 of SELECT list contains nonaggregated column 'sampleCart.p.id'; this is incompatible with sql_mode=only_full_group_by
I checked with just image table and product table ,GROUP_CONCAT was working with linking these 2 tables . but this is happening after linking more than 2 tables .
QUERY WITH OUT GROUP_CONCAT
select p.id,p.name as entityName,
pi.name,
pi.description,
pi.language,
im.image,
ci.name as categoryname
from products p,
productInformation pi,
product_attributes pa,
images im,
categoryInformation ci,
categories c
where ci.category=c.id
and ci.language='en'
and c.id = p.category and p.category in (1,2)
and im.entityid=p.id and im.type='product' and pi.language='en'
and pi.productid=p.id and pa.attributevalueid in (2)
and p.id=pa.productid and p.name like '%p%' and p.price between 0 and 15 ;
RESULT WITH OUT GROUP_CONCAT
+----+------+-------+----------+----+-----------+------+---------------+----------+-------------+
| id | name | price | category | id | productid | name | description | language | image |
+----+------+-------+----------+----+-----------+------+---------------+----------+-------------+
| 1 | pen | 10 | 2 | 1 | 1 | pen | this is a pen | en | 12939.jpg |
| 1 | pen | 10 | 2 | 1 | 1 | pen | this is a pen | en | 2932929.jpg |
+----+------+-------+----------+----+-----------+------+---------------+----------+-------------+
EXPECTED RESULT
+----+------+-------+----------+----+-----------+------+---------------+----------+------------------------------------+
| id | name | price | category | id | productid | name | description | language | image |
+----+------+-------+----------+----+-----------+------+---------------+----------+------------------------------------+
| 1 | pen | 10 | 2 | 1 | 1 | pen | this is a pen | en | 12939.jpg;2983.jpg;30940.jpg |
+----+------+-------+----------+----+-----------+------+---------------+----------+------------------------------------+
Please help .
Thanks in Advance

There is few problem in your question :
1- To join the tables it's better to use Inner Join or Left Join like this :
SELECT p.id,
p.name as entityName,
pi.name,
pi.description,
pi.language,
im.image,
ci.name as categoryname
FROM products p
INNER JOIN productInformation pi ON pi.productid=p.id
INNER JOIN images im ON im.entityid=p.id
INNER JOIN categories c ON c.id = p.category
INNER JOIN categoryInformation ci ON ci.category=c.id
WHERE ci.language='en'
and p.category in (1,2)
im.type='product' and pi.language='en'
pa.attributevalueid in (2)
p.name like '%p%' and p.price between 0 and 15
It's more "readable" in my opinion and you are following the SQL recommendation.
2- In your output and the expected result, you are not using the same columns in the select
So I won't take care of your output and just according to your query :
SELECT p.id,p.name as entityName,
pi.name,
pi.description,
pi.language,
GROUP_CONCAT(im.image, ";"),
ci.name as categoryname
FROM products p
INNER JOIN productInformation pi ON pi.productid=p.id
INNER JOIN images im ON im.entityid=p.id
INNER JOIN categories c ON c.id = p.category
INNER JOIN categoryInformation ci ON ci.category=c.id
WHERE ci.language='en'
and p.category in (1,2)
im.type='product' and pi.language='en'
pa.attributevalueid in (2)
p.name like '%p%' and p.price between 0 and 15
GROUP BY p.id,
entityName,
pi.name,
pi.description,
pi.language,
categoryname

#4givN Query is fixed now
Updated Query
select p.id,p.name as entityName,pi.description,pi.language,GROUP_CONCAT(im.image SEPARATOR ';') as images,ci.name as categoryname from products p,productInformation pi,product_attributes pa,images im,categoryInformation ci,categories c where ci.category=c.id and ci.language='en' and c.id = p.category and p.category in (1,2) and im.entityid=p.id and im.type='product' and pi.language='en' and pi.productid=p.id and pa.attributevalueid in (2) and p.id=pa.productid and p.name like '%p%' and p.price between 0 and 15 group by p.id, p.name, pi.name, pi.description, pi.language,ci.name;
RESULT
+----+------------+---------------+----------+--------------+--------------+
| id | entityName | description | language | images | categoryname |
+----+------------+---------------+----------+--------------+--------------+
| 1 | pen | this is a pen | en | 12.jpg;2.jpg | laptops |
+----+------------+---------------+----------+-----------------------+-----+

Related

MySQL select from two table based on multiple conditions in same table

I'm trying to build a filter to quickly find the right product based on some specifications. But I can't get the MySQL to work. Been gooogling for a while now but can't find a similar question. I hope you can help me.
This is the products table
--------------------
| id | name |
--------------------
| 1 | Product 1 |
| 2 | Product 2 |
| 3 | Product 3 |
--------------------
This is the relation table for the specifications
--------------------------------
| id | specs_id | prod_id |
--------------------------------
| 1 | 1 | 1 |
| 2 | 5 | 1 |
| 3 | 6 | 2 |
| 4 | 9 | 3 |
| 5 | 11 | 2 |
---------------------------------
This is the MySQL how I want it to work.
$sql = "SELECT p.id, p.name
FROM products p
JOIN specs s ON p.id = s.prod_id
WHERE s.specs_id = 1
AND s.specs_id = 5
AND s.specs_id = 7
GROUP BY p.id";
This example will give no result
$sql = "SELECT p.id, p.name
FROM products p
JOIN specs s ON p.id = s.prod_id
WHERE s.specs_id = 1
AND s.specs_id = 5
GROUP BY p.id";
This will return product with ID 1
Item_id does not exist in your table. You also used AND insted of OR, thus no entry could match. None can have the specs_id 2,5, and 7 at the same time.
SELECT p.id, p.name
FROM products p
JOIN specs s
ON p.id = s.prod_id
WHERE s.specs_id = 5
OR s.specs_id = 2
OR s.specs_id = 7
GROUP BY p.id;
Maybe OR or IN is what you are looking for:
SELECT DISTINCT p.id, p.name
FROM products p
JOIN specs s ON p.id = s.prod_id
WHERE s.specs_id IN (1,5);
or
SELECT DISTINCT p.id, p.name
FROM products p
JOIN specs s ON p.id = s.prod_id
WHERE s.specs_id=1 OR s.specs_id=5;
Also, use DISTINCT instead of GROUP BY if you do not have aggregate functions.
You can do like first filter specs table with required specs_id and then make join that result with products table.
select p.id, p.name from
(select * from products p ) p
join (select * from specs where specs_id in (1,5,7)) s
on p.id = s.prod_id
group by p.id

SQL - Join multiple tables and count()

I am trying to count the number of results in a column after joining a table and I am having a hard time getting my query to work.
In the end result, I need to get a table with the product id, product name and the number of medias for each product.
This is what I have so far:
SQL
select
p.id,
p.name,
count(distinct mp.media_id)
from products as p
left join medias_products as mp
on mp.product_id = p.id
group by mp.media_id
order by p.id
These are the tables:
Medias
Id | client id
------ | ---------
1 | 1
2 | 2
Products
id | name | client_id
------ | -------- | ---------
1 | product1 | 1
2 | product2 | 2
medias_products
product_id | media_id
---------- | --------
1 | 2
2 | 1
Client
id | name
------ | -----
1 | Peter
2 | John
In addition, I'd like to find another query that would give me the results filtered by an specific client id.
Can someone please shed some light and share the knowledge.
Thanks in advance.
Try this:
select
p.id,
min(p.name) as name,
count(distinct mp.media_id) as medias
from products as p
left join medias_products as mp
on mp.product_id = p.id
group by p.id
order by p.id
For your second query:
select
p.id,
min(p.name) as name,
count(distinct mp.media_id) as medias
from products as p
inner join medias_products as mp
on mp.product_id = p.id
inner join medias as m
on m.id = mp.media_id
inner join clients as c
on c.id = m.client_id
where c.id = <your client's id>
group by p.id
order by p.id
Shouldn't you GROUP BY p.id instead of mp.media_id? That is
select
p.id,
p.name,
count(distinct mp.media_id)
from
products as p
left join medias_products as mp
on p.id = mp.product_id
group by p.id
order by p.id

create single query to fetch data from tables as seperate rows

i am thinking if there is a better way to query product, product options and product option choices from database
my database structure is like:
product table (product_id, product_name)
product_options table (option_id, option_name, product_id)
product_optionChoices (Choice_id, choice_name, Option_id)
i want a single query that return all product and options in seperate rows like:
--------------------------------------------------------------------------------
| product_id | product_name | option_id | option_name | choiceId | choice_name |
| 1 | shoes | | | | |
| 1 | | 1 | choose color| | |
| | | 1 | | 1 | red |
| | | 1 | | 2 | blue |
--------------------------------------------------------------------------------
right now i am using 3 sepearte queries to get product, product option and product_optionChoices and appending the query together using QueryAddRow in coldfusion.
Thanks
Maybe this solution helps you even if i don't like it.
This returns exactly what you want (UPDATED).
SELECT p.product_id, p.product_name, '' as option_id, '' as option_name, '' as choiceId, '' as choice_name FROM `product` p
UNION ALL
SELECT pr.product_id as product_id, '' as product_name, o.option_id, o.option_name, '' as choiceId, '' as choice_name FROM `product_options` o
INNER JOIN product pr
ON pr.product_id = o.product_id
UNION ALL
SELECT '' as product_id, '' as product_name, op.option_id as option_id, '' as option_name, c.choice_Id, c.choice_name FROM `product_optionChoices` c
INNER JOIN product_options op
ON op.option_id = c.option_id
This works for SQL Server
SELECT P.product_id, P.product_name, PO.option_id, PO.option_name, POC.choiceId, POC.choice_name
FROM product P LEFT OUTER JOIN product_options PO on P.product_id = PO.product_id
LEFT OUTER JOIN product_optionChoices POC on POC.option_id = PO.Option_id

MySQL show relations MANY-MANY by condition

There are two tables:
partner
id | name
--------------
1 | partner_1
2 | partner_2
3 | partner_3
4 | partner_4
contract
id | name | is_active
---------------------------
1 | contract_1 | 1
2 | contract_2 | 0
3 | contract_3 | 1
4 | contract_4 | 0
5 | contract_5 | 0
There is a third table that relates the previous two tables with many-to-many relationship
partner_contract
partner_id | contract_id
------------------------
1 | 1
1 | 2
2 | 3
2 | 2
2 | 4
3 | 5
Each partner can have several contracts, among which ONLY ONE can be active and some inactive .
Also the partner may not have contract at all.
I need a query that displays all the partners together with the active contract. If partner dont' have an active contract, display NULL.
partner_id | partner_name | contract_name
-----------------------------------------
1 | partner_1 | contract_1
2 | partner_2 | contract_3
3 | partner_3 | NULL
4 | partner_4 | NULL
I found a solution, but it seems to me that it is not perfect .
SELECT
p.id AS partner_id,
p.name AS partner_name,
active_contract.name AS contract_name
FROM partner p
LEFT JOIN (
SELECT *
FROM contract c
LEFT JOIN partner_contract pc on pc.contract_id = c.id
WHERE c.is_active = 1
) active_contract
ON active_contract.partner_id = p.id
Is there a more elegant solution?
Ray's (deleted) query is close to the right solution. The condition on the contract should go in the on clause, not the where clause:
SELECT p.id AS partner_id, p.name AS partner_name, c.name AS contract_name
FROM partner p LEFT JOIN
partner_contract pc
ON p.id = pc.partner_id LEFT JOIN
contract c
ON pc.contract_id = c.id AND c.is_active = 1;
EDIT:
Okay, the above is wrong. This can be fixed with a group by:
SELECT p.id AS partner_id, p.name AS partner_name, MAX(c.name) AS contract_name
FROM partner p LEFT JOIN
partner_contract pc
ON p.id = pc.partner_id LEFT JOIN
contract c
ON pc.contract_id = c.id AND c.is_active = 1
GROUP BY p.id, p.name;
The more elegant solution (in my opinion):
SELECT p.*,
(select name
from partner_contract pc join
contract c
on pc.contract_id = c.id AND c.is_active = 1
where p.id = pc.partner_id
) as contract_name
FROM partner p;
SQL Fiddle
This can take advantage of indexes and does not require aggregation.

How to mysql distinct one of many count fields when GROUP BY doesn't work?

I've a database with products, manufactors and categories of this products and information about name of manufactors, products and if those products have images.
But in this database are duplicated products with different IDs. Only thing I can identify them is their name.
Now I've a query where I want see how many products per manufactorer and per category were in my database and count also the number of products with images.
-----------------------------------------------------
| manufactor | category | products | productsImages |
|------------|----------|----------|----------------|
| manu-1 | cat-1 | 5 | 3 |
|------------|----------|----------|----------------|
| manu-1 | cat-2 | 15 | 8 |
|------------|----------|----------|----------------|
| manu-2 | cat-1 | 11 | 0 |
|------------|----------|----------|----------------|
| manu-3 | cat-2 | 5 | 4 |
|------------|----------|----------|----------------|
| manu-3 | cat-3 | 9 | 4 |
|------------|----------|----------|----------------|
My approach looks like:
SELECT m.`name` AS manufactor,
pg.`name` AS category,
COUNT(p.`name`) AS products,
COUNT(pi.`idImage`) AS productsImages
FROM `product` AS p
LEFT JOIN `product_image` AS pi ON pi.`idProduct` = p.`id`
INNER JOIN `manufacturer` AS m ON m.`id` = p.`idManufacturer`
INNER JOIN `product_groupname` AS pg ON pg.`id` = p.`idProductGroup`
GROUP BY p.`idManufacturer`, p.`idProductGroup`
ORDER BY m.`name`, p.`idProductGroup`;
I can't group by p.name because then I'd get a result row for each product.
Do COUNT(DISTINCT(p.name)) didn't help either.
So any suggestions or will I have do to subqueries?
If you want to count the distinct names where pi.`idImage` IS NOT NULL you can use the following:
SELECT m.`name` AS manufactor,
pg.`name` AS category,
COUNT(DISTINCT p.`name`) AS products,
COUNT(DISTINCT CASE
WHEN pi.`idImage` IS NOT NULL THEN p.`name`
ELSE NULL
END) AS productsImages
FROM `product` AS p
LEFT JOIN `product_image` AS pi ON pi.`idProduct` = p.`id`
INNER JOIN `manufacturer` AS m ON m.`id` = p.`idManufacturer`
INNER JOIN `product_groupname` AS pg ON pg.`id` = p.`idProductGroup`
GROUP BY p.`idManufacturer`, p.`idProductGroup`
ORDER BY m.`name`, p.`idProductGroup`;
See comments on question - distinct on p.name is the solution.
SELECT m.`name` AS manufactor,
pg.`name` AS category,
COUNT(DISTINCT(p.`name`)) AS products,
COUNT(pi.`idImage`) AS productsImages
FROM `product` AS p
LEFT JOIN `product_image` AS pi ON pi.`idProduct` = p.`id`
INNER JOIN `manufacturer` AS m ON m.`id` = p.`idManufacturer`
INNER JOIN `product_groupname` AS pg ON pg.`id` = p.`idProductGroup`
GROUP BY p.`idManufacturer`, p.`idProductGroup`
ORDER BY m.`name`, p.`idProductGroup`;