SELECT li_1.carrier, li_1.product_id, li_1.quantity, products_description.products_name, sites.sites_id, sites.sites_name, counted_table.counted
FROM inventory li_1
INNER JOIN products_description ON li_1.product_id = products_description.products_id
INNER JOIN sites ON products_description.data = sites.data
INNER JOIN (
SELECT SUM( li_2.quantity ) AS counted
FROM inventory li_2
WHERE li_1.product_id = li_2.product_id
) counted_table
GROUP BY li_1.product_id
ORDER BY li_1.id DESC
I'm attempting to use the parent id (product_id) to count the total amount of quantity for each product in the subquery - But I only get the standard mysql error message.
So something like
id | quantity | total
---------------------------------
0001 | 2 | 6
| |
0001 | 4 | 6
What could be wrong?
if you change sub-query, it could be fixed
SELECT li_1.carrier, li_1.product_id, li_1.quantity, products_description.products_name, sites.sites_id, sites.sites_name, counted_table.counted
FROM inventory li_1
INNER JOIN products_description ON li_1.product_id = products_description.products_id
INNER JOIN sites ON products_description.data = sites.data
INNER JOIN (
SELECT product_id,SUM( li_2.quantity ) AS counted
FROM inventory li_2
GROUP BY li_2.product_id
) counted_table ON li_1.product_id = counted_table.product_id
ORDER BY li_1.id DESC
Related
I've the follow SQL schema:
+----------+
| products |
+----------+
| id |
| name |
+----------+
^ 8
|
v 1
+-------------+
| values |
+-------------+
| value |
| product_id |
| property_id |
+-------------+
^ 8
|
v 1
+------------+
| properties |
+------------+
| id |
| name |
+------------+
One product has many properties and a property belongs to many products. The values table is the join table for the many_to_many association between products and properties. And in this table is saved the value of the property for a product.
Now I'm looking for a query to select all products with property x with value a, and property y with value b ecc. My try is this query but return no records:
SELECT DISTINCT
products.*
FROM
products
INNER JOIN
product_values
ON product_values.product_id = products.id
INNER JOIN
properties
ON properties.id = product_values.property_id
WHERE
(properties.name = 'size' AND product_values.value = 'big')
AND (properties.name = 'color' AND product_values.value = 'red')
If possible I need a query with no nested select.
Since a property can not be color and size at the same time you need to use OR in your where clause. Then group the data and check if both are in the group with having
SELECT products.id, products.name
FROM `products`
INNER JOIN `product_values` ON `product_values`.`product_id` = `products`.`id`
INNER JOIN `properties` ON `properties`.`id` = `product_values`.`property_id`
WHERE (properties.name = 'size' AND product_values.value = 'big')
OR (properties.name = 'color' AND product_values.value = 'red')
GROUP BY products.id, products.name
HAVING count(distinct properties.name) = 2
I would do this using group by and having:
select pv.product_id
from product_values pv join
properties p
on pv.property_id = p.id
where (p.name, v.value) in ( ('size', 'big'), ('color', 'red') )
group by pv.product_id
having count(distinct p.name) = 2;
Another approach using sum to filter multiple attributes for an entity
SELECT
`p`.*
FROM
`products` p
INNER JOIN `product_values` v
ON `v`.`product_id` = `p`.`id`
INNER JOIN `properties` pr
ON `pr`.`id` = `v`.`property_id`
GROUP BY p.id
HAVING SUM (pr.name = 'size' AND v.value = 'big')
AND SUM(pr.name = 'color' AND v.value = 'red')
This is my situation.
I have 3 tables
Orders
- id status deleted
Order Lines
- related_id related_model quantity
Products
- id code price price_purchase
I want to create a list with all products. The amount of times they are purchased and a sum of the gross margin (price - price_purchase). It must only use orders lines with the related model set to 'products'. And secondly it must only pick orders with the status set to 'paid, processing, sent, ready_for_pickup or picked_up' and with the order not deleted.
So this would be the result I want:
id | code | purchases | value
-------------------------------
1 | code1 | 7 | 57,05
2 | code2 | 122 | 254,98
3 | code3 | 0 | 0,00
This is the SQL query I have so far:
SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
LEFT JOIN shop_orders_lines sol ON sol.related_id = p.id
AND sol.related_model = 'products'
LEFT JOIN shop_orders so ON so.id = sol.order_id
WHERE so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
GROUP BY p.id
It returns the correct data. But not all problems. That is my problem. I a lot of different methods like sub queries and other methods but can't seem to solve the problem. I know the problem is my LEFT join, but don't know a solution to my problem.
I'm using MySQL Workbench.
Any help is welcome.
Your joins are wrong. You need to identify the order lines to consider separately from and prior to forming the LEFT JOIN with the product details. An inline view could help:
SELECT
p.id,
p.code,
IFNULL(SUM(ordered_item.quantity) , 0) as purchases ,
sum((p.price - p.price_purchase) * ordered_item.quantity) as value
FROM
products p
LEFT JOIN (
SELECT
sol.related_id AS related_id,
sol.quantity AS quantity
FROM
shop_orders_lines sol
INNER JOIN shop_orders so
ON so.id = sol.order_id
WHERE
so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
AND sol.related_model = 'products'
) ordered_item
ON ordered_item.related_id = p.id
GROUP BY p.id
Move outer table conditions from WHERE to ON, otherwise the OUTER JOIN works like a regular INNER JOIN:
SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
LEFT JOIN shop_orders_lines sol ON sol.related_id = p.id
AND sol.related_model = 'products'
LEFT JOIN shop_orders so ON so.id = sol.order_id AND
so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
GROUP BY p.id
Is p.id the whole primary key for that table? If not, you need to find out how to treat p.code. (Either list in GROUP BY, or use as argument to aggregate function.)
Another try:
SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
JOIN shop_orders_lines sol ON sol.related_id = p.id
AND sol.related_model = 'products'
WHERE EXISTS (select 1 from shop_orders so
where so.id = sol.order_id
AND so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0)
GROUP BY p.id
Table transport
Id | FirstLevSubcat | SecondLevSubcat | ThirdLevSubcat
--------------------------------------------------------
8 | 4 | 27 | 1418
Table categories
Id | CategoriesUrl
--------------------
4 | cars
27 | audi
1418 | audi-100
Query if not to use categories table (without inner join) would be like
SELECT count(*) FROM transport
WHERE FirstLevSubcat = 4 AND SecondLevSubcat = 27 AND ThirdLevSubcat = 1418
Trying to get the same result using INNER JOIN
SELECT count(*) FROM transport main_table
INNER JOIN categories cat_table_first ON cat_table_first.IdRows = main_table.FirstLevSubcat
INNER JOIN categories cat_table_second ON cat_table_second.IdRows = main_table.SecondLevSubcat
INNER JOIN categories cat_table_third ON cat_table_third.IdRows = main_table.ThirdLevSubcat
WHERE
cat_table_first.CategoriesUrl = 'cars'
AND cat_table_second.CategoriesUrl = 'audi'
AND cat_table_third.CategoriesUrl = 'audi-100'
At first sight all works
But is such query ok? May be can improve something?
Your query is correct. You can also do it in following way:
SELECT count(*) FROM transport main_table
INNER JOIN categories cat_table_first ON cat_table_first.IdRows = main_table.FirstLevSubcat and cat_table_first.CategoriesUrl = 'cars'
INNER JOIN categories cat_table_second ON cat_table_second.IdRows = main_table.SecondLevSubcat and cat_table_second.CategoriesUrl = 'audi'
INNER JOIN categories cat_table_third ON cat_table_third.IdRows = main_table.ThirdLevSubcat and cat_table_third.CategoriesUrl = 'audi-100'
You can also do it using 3 EXISTS block.
SELECT count(*) FROM transport main_table
WHERE
EXISTS (SELECT NULL FROM categories WHERE main_table.FirstLevSubcat=categories.IdRows AND categories.CategoriesUrl ='cars')
AND
EXISTS (SELECT NULL FROM categories WHERE main_table.SecondLevSubcat=categories.IdRows AND categories.CategoriesUrl ='audi')
AND
EXISTS (SELECT NULL FROM categories WHERE main_table.ThirdLevSubcat=categories.IdRows AND categories.CategoriesUrl ='audi-100')
I've got a SELECT with multiple JOINS for a paginated Tableview. In general this is working for unfiltered results.
The query looks like this:
SELECT seltable.*,
tbl2.name AS tbl2name,
tbl3.name AS tbl3name,
tbl4.name AS tbl4name
FROM
( SELECT * FROM selecttable
WHERE value = 99
ORDER BY datetime DESC
LIMIT 50 OFFSET 0 )
AS seltable
LEFT JOIN table1 AS tbl1 ON seltable.tbl1_uid = tbl1.uid
LEFT JOIN table2 AS tbl2 ON tbl1.tbl2_uid = tbl2.uid
LEFT JOIN table3 AS tbl3 ON tbl2.tbl3_uid = tbl3.uid
LEFT JOIN table4 AS tbl4 ON tbl3.tbl4_uid = tbl4.uid;
Now I've got no clue how to accomplish filtering the results with a condition related to one of the join tables.
When I just set a:
LEFT JOIN tablex AS table ON foreign_table.tblx_uid = table.uid AND {condition}
this condition regards only to the 50 results of the nested SELECT.
Is there any way to achieve using WHERE clauses on the JOIN tables in this scenario?
For sample data see http://sqlfiddle.com/#!2/fad4d/2
Expected results:
to get x team records limited to 5 team uids, where Tournament2 is one of the related tournaments for the team.
Best regards
w1ll1
Try not controlling the pagination in that subquery, instead just use a more conventional query with a composite where clause. HOWEVER, because you are using left joins take care adding filters through the where clause that would override the outer join to produce the effect of an inner join.
SELECT seltable.*,
tbl2.name AS tbl2name,
tbl3.name AS tbl3name,
tbl4.name AS tbl4name
FROM selecttable AS seltable
LEFT JOIN table1 AS tbl1 ON seltable.tbl1_uid = tbl1.uid
LEFT JOIN table2 AS tbl2 ON tbl1.tbl2_uid = tbl2.uid
LEFT JOIN table3 AS tbl3 ON tbl2.tbl3_uid = tbl3.uid
LEFT JOIN table4 AS tbl4 ON tbl3.tbl4_uid = tbl4.uid
WHERE seltable.value = 99
...
ORDER BY seltable.datetime DESC
LIMIT 50 OFFSET 0
Alternatively use more subqueries, like this:
SELECT seltable.*,
tbl2.name AS tbl2name,
tbl3.name AS tbl3name,
tbl4.name AS tbl4name
FROM
( SELECT * FROM selecttable
WHERE value = 99
ORDER BY datetime DESC
LIMIT 50 OFFSET 0 )
AS seltable
LEFT JOIN ( SELECT uid, name
FROM table1
WHERE 1=1 -- amend to suit
) AS tbl1 ON seltable.tbl1_uid = tbl1.uid
LEFT JOIN ( SELECT uid, name
FROM table2
WHERE 1=1 -- amend to suit
) AS tbl2 ON tbl1.tbl2_uid = tbl2.uid
LEFT JOIN ( SELECT uid, name
FROM table3
WHERE 1=1 -- amend to suit
) AS tbl3 ON tbl2.tbl3_uid = tbl3.uid
LEFT JOIN ( SELECT uid, name
FROM table4
WHERE 1=1 -- amend to suit
) AS tbl4 ON tbl3.tbl4_uid = tbl4.uid;
Here is another attempt, based on your sqlfiddle it appears that INNER JOINS may be used:
SELECT theteam.*,
trnmnt.name AS tournamentname,
cat.name AS categoryname,
sport.name AS sportname
FROM (
SELECT * FROM team
ORDER BY team.name ASC )
AS theteam
INNER JOIN tournament_team AS tntm ON tntm.team_uid = theteam.uid
INNER JOIN tournament AS trnmnt ON tntm.tournament_uid = trnmnt.uid AND trnmnt.name = 'Tournament2'
INNER JOIN category AS cat ON trnmnt.category_uid = cat.uid
INNER JOIN sport ON cat.sport_uid = sport.uid
LIMIT 5 OFFSET 0
;
The result of that query is:
| UID | NAME | TOURNAMENTNAME | CATEGORYNAME | SPORTNAME |
|-----|--------|----------------|--------------|-----------|
| 2 | Team02 | Tournament2 | Germany | Soccer |
| 3 | Team03 | Tournament2 | Germany | Soccer |
| 4 | Team04 | Tournament2 | Germany | Soccer |
| 5 | Team05 | Tournament2 | Germany | Soccer |
| 6 | Team06 | Tournament2 | Germany | Soccer |
Here's my code as is, working, but very slow:
$graded = R::getAll("SELECT posts.id, posts.discussion, rating.rating, rating.itemid
FROM uv_forum_posts posts
JOIN uv_rating rating ON ( posts.id = rating.itemid )
WHERE posts.discussion = :discussion_id
GROUP BY posts.userid",
array(':discussion_id' => $discussion['id']));
$total = R::getAll("SELECT posts.userid
FROM uv_forum_posts posts
WHERE posts.discussion = :discussion_id
GROUP BY userid",
array(':discussion_id' => $discussion['id']));
$percentages[] = count($graded) / count($total) * 100;
$graded represents all rows that have a rating.
$total represents all user participation, regardless of being graded or not.
I'm only interested in the numerical values of the resulting sets, can I combine these two MySQL calls into a single call that returns two numbers graded and total?
If I correctly understand your requirements you can try
SELECT p.userid,
COUNT(*) total,
COUNT(r.itemid) graded
FROM uv_forum_posts p LEFT JOIN
uv_rating r ON p.id = r.itemid
WHERE p.discussion = :discussion_id
GROUP BY p.userid
Output:
| USERID | TOTAL | GRADED |
---------------------------
| 1 | 8 | 2 |
| 2 | 4 | 4 |
SQLFiddle
UPDATE: If you just want grand total for all posts and users then
SELECT COUNT(*) total,
COUNT(r.itemid) graded
FROM uv_forum_posts p LEFT JOIN
uv_rating r ON p.id = r.itemid
WHERE p.discussion = 1
Output:
| TOTAL | GRADED |
------------------
| 12 | 6 |
SQLFiddle
You could simply use a query as in the format :
Select
( SELECT posts.id, posts.discussion, rating.rating, rating.itemid
FROM uv_forum_posts posts
JOIN uv_rating rating ON ( posts.id = rating.itemid )
WHERE posts.discussion = :discussion_id
GROUP BY posts.userid,
array(':discussion_id' => $discussion['id']))) gradeCount,
(SELECT posts.userid
FROM uv_forum_posts posts
WHERE posts.discussion = :discussion_id
GROUP BY userid,
array(':discussion_id' => $discussion['id'])))totalCount