I have tables like
products product_attributes
================== ========================================
| id | name | | id | product_id | attribute | value |
================== ========================================
| 1 | product 1 | | 1 | 1 | min | 2 |
| 2 | product 2 | | 2 | 1 | max | 5 |
| 3 | product 3 | | 3 | 2 | min | 10 |
| 3 | product 3 | | 4 | 2 | max | 15 |
| .. | ... | | 5 | 3 | min | 1 |
================== | 6 | 3 | max | 100 |
| .. | ... | ... | ... |
========================================
I want to get all the products that fall within a range
I can successfully get a list of the ids that fall with-in the range using
SELECT p.id
FROM `products` p INNER JOIN `product_attributes` AS pa ON p.id = pa.product_id
WHERE pa.`min` <= 5 AND pa.`max` >= 5 GROUP BY p.id
This gives me a list of the ids that i need.
What i can not get to work is to get a TOTAL count of the ids instead of a list so i can not use the group by and then when i do that it messes up the count.
Is the only way to do this is by using the select above in a subselect and counting the
results?
Thanks
Given the structure above, where min and max are on different rows, I would use this:
select count(id) from (
select p.id
from
`products` p INNER JOIN `product_attributes` AS pa
ON p.id = pa.product_id
where (pa.attribute='min' and pa.value>=5) OR
(pa.attribute='max' and pa.value<=5)
group by p.id
having count(*)=2
) s
Just replace p.id with COUNT(1) in the query.
SELECT COUNT(1)
FROM `products` p
INNER JOIN `product_attributes` AS pa
ON p.id = pa.product_id
WHERE pa.`min` <= 5
AND pa.`max` >= 5
GROUP BY p.id
One approach is to apply the veneer of normalisation to the eav model before attempting to extract any information from it. In this case that might look like this:
SELECT product_id
, MAX(CASE WHEN attribute = 'min' THEN value END) `min`
, MAX(CASE WHEN attribute = 'max' THEN value END) `max`
FROM product_attributes
GROUP
BY product_id;
+------------+------+------+
| product_id | min | max |
+------------+------+------+
| 1 | 2 | 5 |
| 2 | 10 | 15 |
| 3 | 1 | 100 |
| ... | ... | ... |
+------------+------+------+
Now, what was your question again?
Try a select count(*) from your select statement.
Related
I have these three tables:
products
+----+--------+
| id | QRCode |
+----+--------+
| 1 | 1000 |
| 2 | 1001 |
+----+--------+
prices
+----+---------+------------+
| id | price | product_id |
+----+---------+------------+
| 2 | $100001 | 1 |
| 3 | $100002 | 1 |
| 4 | $90001 | 2 |
| 5 | $90002 | 2 |
+----+---------+------------+
colors
+----+--------+-------------+
| id | color | product_id |
+----+--------+-------------+
| 1 | ffffff | 1 |
| 2 | f2f2f2 | 1 |
| 4 | aaaaaa | 2 |
| 5 | a3a3a3 | 2 |
+----+--------+-------------+
I would like to merge these three in a way that returns:
group_concat colors based on product_id
retrieves last record of each grouped price
This is the desired output:
+--------+----------------+-------------+-------------+
| QRCode | colors | price | product_id |
+--------+----------------+-------------+-------------+
| 1000 | ffffff, f2f2f2 | $100002 | 1 |
| 1001 | aaaaaa, a3a3a3 | $90002 | 2 |
+--------+----------------+-------------+-------------+
Things I tried:
The query below returns product_id of last record of each grouped price
SELECT product_id FROM price where id IN
(SELECT max(id) FROM price
GROUP BY product_id)
Then I tried to put query above in this query as a subquery
SELECT products.QRCode, priceSubQ.price, GROUP_CONCAT(colors.color) as colors FROM products
INNER JOIN colors on colors.product_id = products.id
INNER JOIN ( /* I put query above here */ ) as priceSubQ ON priceSubQ.product_id = products.id
GROUP BY products.id
What am I doing wrong?
I came across this link which helped me understand the problem
Changed inner query to:
SELECT product_id FROM ANY_VALUE(price) where id IN
(SELECT max(id) FROM price
GROUP BY product_id) group by product_id
solved my problem.
Something like the following should work (not tested)..
SELECT
products.QRCode,
priceSubQ.price,
GROUP_CONCAT(colors.color) as colors
FROM
products
LEFT JOIN colors
ON colors.product_id = products.id
LEFT JOIN (
SELECT
MAX(p1.id) as p1maxId,
p2.price AS price,
p2.product_id AS product_id
FROM
prices p1
INNER JOIN prices p2
ON p1.p1maxId = p2.id
GROUP BY
p1.product_id
) AS priceSubQ
ON priceSubQ.product_id = products.id
GROUP BY
products.id
I have 2 tables:
table a
+----------+------------+------------+
|session_id| product_id | orders |
+----------+------------+------------+
| 1 | 11 | 0 |
| 1 | 22 | 2 |
| 1 | 34 | 1 |
| 2 | 11 | 0 |
| 3 | 43 | 0 |
| 3 | 11 | 1 |
+----------+------------+------------+
table b:
+-----------+--------------+
|product_id |category_id |
+-----------+--------------+
| 11 | 100 |
| 12 | 101 |
| 34 | 102 |
| 22 | 103 |
| 43 | 104 |
| 13 | 105 |
+-----------+--------------+
What I want is a table which consists of how many category_id were there in each session_id and also total orders placed in that session_id
+-----------+--------------------+--------+
|session_id | count(category_id) | orders |
+-----------+--------------------+--------+
| 1 | 3 | 3 |
| 2 | 1 | 0 |
| 3 | 2 | 1 |
+-----------+--------------------+--------+
I tried:
select a.session_id,count(b.category_id),sum(a.orders) from a
join table b
on a.product_id = b.product id
is this query right?
Please help me. I am a beginner
I tried with 2 methods
1)...SELECT a.session_id,COUNT(b.category_id),SUM(a.orders) FROM #a a
LEFT JOIN #b b
ON a.product_id = b.product_id GROUP BY a.session_id
GROUP BY a.Session_ID
2...) SELECT D.SESSION_ID,COUNT(CATEGORY_ID),SUM(D.ORDERS) FROM #A D
OUTER APPLY
(
SELECT CATEGORY_ID,PRODUCT_ID FROM #B B
WHERE D.PRODUCT_ID = B.PRODUCT_ID
) A
GROUP BY D.SESSION_ID
GO
Just use left join for showing all result from table A
by using only join its show the result exist in both table only.
SELECT a.session_id,COUNT(b.category_id),SUM(a.orders) FROM a
LEFT JOIN b
ON a.product_id = b.product_id GROUP BY a.`session_id`
Ofcourse you have t join tha tables, then group with the field you want.
SELECT a.Session_ID, Count(Category_ID) CategoryCount, SUM(Orders) NumberOfOrders
FROM a
LEFT OUTER JOIN b
ON a.Product_ID = b. Product ID
GROUP BY a.Session_ID
Personally, and since I don't have any info on the data structure I prefered using the LEft outer join since in case the product_id had no category, then no results of this product will show.
(unless each product should have a category, or the user needs only the products that has a category, you have to use the INNER JOIN)
I have two tables:
Problems
id | name
Responses
id | problem_id | user_id | value
I have the following statement.
SELECT
`problems`.name,
problem_id,
sum(value) as knowledge,
COUNT(*) as attempts FROM `responses`
LEFT JOIN `problems` ON `problems`.id = `responses`.problem_id
WHERE problem_id IS NOT NULL AND user_id = 4
GROUP BY problem_id
It produces a list like so:
| name | problem_id | knowledge | attempts |
| NULL | 1 | 6 | 6 |
| NULL | 2 | 5 | 6 |
| NULL | 3 | 4 | 6 |
| NULL | 4 | 3 | 5 |
I'm missing something and I would be grateful if someone could help format to:
| name | problem_id | knowledge | attempts |
| Problem A | 1 | 6 | 6 |
| Problem B | 2 | 5 | 6 |
| Problem C | 3 | 4 | 6 |
| Problem D | 4 | 3 | 5 |
Try this.
select p.`name`, p.`id`, r.`user_id`, sum(r.`value`) as knowledge
from
`responses` r
join `problems` p on r.`problem_id` = p.`id`
where
r.`user_id` = 4
group by p.`name`, p.`id`
You cannot have in your SELECT something that is neither an aggregate function (like SUM or AVG), nor a variable part of the GROUP BY.
In your case, the name is neither.
Some DBMS might let you do it (MySQL), but the result is unpredictable.
Solution:
SELECT
`problems`.name,
problem_id,
sum(value) as knowledge,
COUNT(*) as attempts FROM `responses`
LEFT JOIN `problems` ON `problems`.id = `responses`.problem_id
WHERE problem_id IS NOT NULL AND user_id = 4
GROUP BY problem_id, problems.name
Is it possible to write this query with INNER JOINs?
SELECT links.product_id AS entity_id, products.sku, links.`linked_product_id` AS linked_entity_id, products2.`sku` AS linked_skus
FROM catalog_product_entity AS products,
catalog_product_link AS links,
catalog_product_entity AS products2
WHERE links.`product_id` = products.`entity_id`
AND links.`linked_product_id` = products2.`entity_id`
Also, catalog_product_link has a column type_id, and I wanted to get only rows with type_id value 1 with AND catalog_product_link.type_id = 1 condition at the end, but it doesn't work. How do I go about getting only records with type_id=1?
I'm having a problem where when I add WHERE links.type_id=1 to the statement, the result comes out wrong. Everything under product_id is the same number (same entity_id/product_id), and everything under sku is NULL. linked_product_id and linked_skus are correct, though.
More information:
catalog_product_entity
| entity_id | sku | ... |
-------------------
| 1 | abc | |
| 2 | qwe | |
| 3 | yui | |
catalog_product_link
| product_id (same as entity_id) | linked_product_id | type_id |
----------------------------------------------------------------
| 1 | 5 | 1 |
| 1 | 6 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
| 3 | 2 | 1 |
| 3 | 4 | 1 |
Something like...
SELECT
p.sku,
l.product_id AS entity_id, l.linked_product_id AS linked_entity_id
FROM catalog_product_entity AS p
INNER JOIN catalog_product_link AS l
ON p.entity_id= l.product_id
WHERE l.type_id = 1
SELECT
links.product_id AS entity_id,
products.sku,
links.linked_product_id AS linked_entity_id,
products2.sku AS linked_skus
FROM catalog_product_link AS links
INNER JOIN
catalog_product_entity AS products ON products.entity_id = links.product_id
INNER JOIN
catalog_product_entity AS products2 ON products2.entity_id = links.linked_product_id
WHERE links.type_id = 1
pardon my question title, I'm not sure what should I put it, I have these two tables as below.
products orders
+------+----------+ +--------+------+-------+
| id | name | | id | qty | pid |
+------+----------+ +--------+------+-------+
| 1 | mouse | | 10001 | 20 | 1 |
| 2 | keyboard | | 10002 | 15 | 3 |
| 3 | headset | | 10004 | 5 | 3 |
+------+----------+ | 10005 | 12 | 2 |
| 10006 | 18 | 1 |
+--------+------+-------+
This is the LEFT JOIN query I am using and the output
SELECT p.id AS No, p.name AS ProductName, o.qty AS Quantity
FROM products AS p
LEFT JOIN orders AS o ON p.id = o.pid
+------+-------------+----------+
| No | ProductName | Quantity |
+------+-------------+----------+
| 1 | mouse | 20 |
| 1 | mouse | 18 |
| 2 | keyboard | 12 |
| 3 | headset | 15 |
| 3 | headset | 5 |
+------+-------------+----------+
What I am trying to achieve is an output as below:
+------+-------------+----------+
| No | ProductName | Quantity |
+------+-------------+----------+
| 1 | mouse | 20 |
| | | 18 |
| 2 | keyboard | 12 |
| 3 | headset | 15 |
| | | 5 |
+------+-------------+----------+
My question is it possible to do so? Any reply and suggestions is greatly appreciate. Thanks.
P/S: I also have tried using the GROUP_CONCAT(qty SEPARATOR ",") but it returns the result in one row as I may have more additional column to add in the Orders table in the future and it will be difficult to read.
Sure, it's possible — and without needing to use variables:
SELECT IF(c.min_oid IS NOT NULL, a.id, NULL) AS No,
IF(c.min_oid IS NOT NULL, a.name, NULL) AS ProductName,
b.qty AS Quantity
FROM products a
JOIN orders b ON a.id = b.pid
LEFT JOIN (
SELECT MIN(id) AS min_oid
FROM orders
GROUP BY pid
) c ON b.id = c.min_oid
ORDER BY a.id,
b.id
Basically what it's doing is if the row is not the minimum order id of a particular product, display blank (NULL), otherwise display the information.
SQLFiddle Demo
In this case you can use MySQL variables. I store the previous product id in the variable #prev, and only if it changes we output the product name.
http://www.sqlfiddle.com/#!2/d5fd6/9
SET #prev := NULL;
SELECT
IF( #prev = p.id, NULL, p.id) AS No,
IF( #prev = p.id, NULL, p.name) AS ProductName,
o.qty AS Quantity
,#prev := p.id
FROM products AS p
LEFT JOIN orders AS o
ON p.id = o.pid