mysql left join duplicate my table rows - why? - mysql

I have 2 tables:
Table1 => product_id, product_quantity => here I have 25 rows.
Table2 => product_hashid, order_quantity => here I have 1 query row.
I build this mysql query:
SELECT SUM(table1.product_quantity) - SUM(order_quantity) AS instocks
FROM table1 -- table.1 in original
LEFT JOIN table2 ON table2.product_hashid = table1.product_id
WHERE table1.product_id = '$thisid'
This query duplicates table2 row with table1. Is there some error in this query?
First, I want to sum all product_quantity from table1 where product_id = '$this' and sum all order_quantity in table2 where product_hashid = '$this' and make (a - b) to display a final result.

Your outline of what you want to do is good, but it isn't what you implemented.
I want to sum all product_quantity from table1 where product_id = '$this' and sum all order_quantity in table2 where product_hashid = '$this' and make (a - b) to display a final result.
Build it up one step at a time.
SELECT SUM(product_quantity) FROM Table1 WHERE Product_ID = '$this';
SELECT SUM(order_quantity) FROM Table2 WHERE Product_HashID = '$this';
SELECT (SELECT SUM(product_quantity) FROM Table1 WHERE Product_ID = '$this') -
(SELECT SUM(order_quantity) FROM Table2 WHERE Product_HashID = '$this')
FROM Dual;
You might observe that the code alignment emphasizes the inconsistent column naming for the product ID columns.
In the more general case:
SELECT Product_ID, SUM(product_quantity) AS Product_Quantity
FROM Table1
GROUP BY Product_ID;
SELECT Product_HashID AS Product_ID, SUM(order_quantity) AS Order_Quantity
FROM Table2
GROUP BY Product_HashID;
SELECT p.Product_ID, p.Product_Quantity - o.Order_Quantity AS SurplusOnHand
FROM (SELECT Product_ID, SUM(product_quantity) AS Product_Quantity
FROM Table1
GROUP BY Product_ID) AS P
JOIN (SELECT Product_HashID AS Product_ID, SUM(order_quantity) AS Order_Quantity
FROM Table2
GROUP BY Product_HashID) AS O
ON O.Product_ID = P.Product_ID;
Sometimes you need to use a LEFT OUTER JOIN; mostly, you don't. Write your SQL assuming you don't until you're sure that you do.
Given the data cardinalities (row counts), you may need to do an LOJ here. You need to manufacture a zero for the order quantity of those products listed in Table1 that are not listed in Table2.
SELECT (SELECT SUM(product_quantity) FROM Table1 WHERE Product_ID = '$this') -
NVL(SELECT SUM(order_quantity) FROM Table2 WHERE Product_HashID = '$this'), 0)
FROM Dual;
SELECT p.Product_ID, p.Product_Quantity - NVL(o.Order_Quantity, 0) AS SurplusOnHand
FROM (SELECT Product_ID, SUM(product_quantity) AS Product_Quantity
FROM Table1
GROUP BY Product_ID) AS P
LEFT OUTER JOIN
(SELECT Product_HashID AS Product_ID, SUM(order_quantity) AS Order_Quantity
FROM Table2
GROUP BY Product_HashID) AS O
ON O.Product_ID = P.Product_ID;

LEFT JOIN will return all of table1 in every case.
http://www.w3schools.com/sql/sql_join_left.asp
Do you actually want just the products in table1 if they appear in table 2? If so, you need simply JOIN (or INNER JOIN)
http://www.w3schools.com/sql/sql_join_inner.asp

I think the issue is your JOIN and your WHERE clause. In this setup, you will return all of the data from table2, which will give you a mess. Your WHERE clause is looking at table1 and limiting the rows there but your JOIN returns all rows from table2 and only those rows from table1 that are equal.
Bottom line: change your join to be an INNER JOIN and your problems will go away.

Related

Sub query with no result

I have two query that I would like to combine into one.
Query 1: SELECT Quantity FROM Table1 WHERE IdProduct = 1234
Query 2: SELECT Supplier FROM Table2 WHERE IdProduct = 1234
Here is what I have done:
SELECT
bloc1.Quantity AS qty,
bloc2.Supplier AS supplier
FROM
(SELECT Quantity FROM Table1 WHERE IdProduct = 1234) bloc1,
(SELECT Supplier FROM Table2 WHERE IdProduct = 1234) bloc2
Most of the time everything goes well, but unfortunately, sometimes one of the two query return no result... In this specific case, the two query "fail".
U can join the two tables table1 and table2 u can do:
SELECT qty,sup
FROM (SELECT Quantity as qty,supplier as sup
FROM Table1
INNER JOIN Table2
ON table1.IdProduct=table2.IdProduct AND IdProduct=1234);
u can check this for more information on joins in mysql https://www.mysqltutorial.org/mysql-join/
Your code is doing a CROSS JOIN of the results of the 2 queries.
So if any of them returns no rows, the result is no rows.
Instead use the result of the 2 queries as columns if you are sure that they will return only 1 row:
SELECT
(SELECT Quantity FROM Table1 WHERE IdProduct = 1234) qty,
(SELECT Supplier FROM Table2 WHERE IdProduct = 1234) supplier
It's remarkable to me that slapping those queries together like that ever works. But if you want it to survive a lack of records in one of these tables, you'll need an OUTER JOIN of some kind. See https://dev.mysql.com/doc/refman/5.7/en/join.html.
You probably want a "full outer join". Unfortunately MySQL does not implement full outer joins (why in this day and age?).
Anyway, you can simulate it with the workaround:
SELECT
bloc1.Quantity AS qty,
bloc2.Supplier AS supplier
FROM (SELECT Quantity FROM Table1 WHERE IdProduct = 1234) bloc1
LEFT JOIN (SELECT Supplier FROM Table2 WHERE IdProduct = 1234) bloc2 on 1 = 1
UNION
SELECT
bloc1.Quantity AS qty,
bloc2.Supplier AS supplier
FROM (SELECT Quantity FROM Table1 WHERE IdProduct = 1234) bloc1
RIGHT JOIN (SELECT Supplier FROM Table2 WHERE IdProduct = 1234) bloc2 on 1 = 1
In MySQL 8.x you can remove the redundancy (and somewhat shorten it) by using CTEs. For example:
with
bloc1 as (SELECT Quantity FROM Table1 WHERE IdProduct = 1234),
bloc2 as (SELECT Supplier FROM Table2 WHERE IdProduct = 1234)
SELECT
bloc1.Quantity AS qty,
bloc2.Supplier AS supplier
FROM bloc1 LEFT JOIN bloc2 on 1 = 1
UNION
SELECT
bloc1.Quantity AS qty,
bloc2.Supplier AS supplier
FROM bloc1 RIGHT JOIN bloc2 on 1 = 1
You can try the below -
select
(SELECT Quantity FROM Table1 WHERE IdProduct = 1234) as qty,
(SELECT Supplier FROM Table2 WHERE IdProduct = 1234) as supplier

mysql sum on JOINED table with different group condition

I have a query as the following
SELECT
sum(price),
count(id),
sum case(when spec='bath' then price else 0 END) as bath_money
FROM
table1
LEFT JOIN table2 ON table1.id = table2.fkt1
LEFT JOIN table3 ON table2.id = table3.fkt2
WHERE 1
group by sale;
Now my problem is that table 3 has 2 rows for each row in Table 2. Table 2 is the one I actually use to add up sales and to sum price but since I need to left join for Table 3 everything is added twice.
Would there be a way of adding up prices of table 2 ignoring all double lines generated by joining Table 3? Otherwise I'd just write another query, but I'd like to know whether I can do a sum ignoring a specific join??
Does this work :
SELECT
sum(price),
count(id),
sum(case when spec='bath' then price else 0 END) as bath_money
FROM table1 t1
LEFT JOIN table2 ON table1.id = table2.fkt1
LEFT JOIN (select * from table3 GROUP BY fkt2) table3a ON table2.id = table3a.fkt2
group by sale;
You can try something like
SELECT
sum(t1.price),
count(t1.id),
sum (case when t2.spec='bath' then t2.price else 0 END) as bath_money
FROM
table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.fkt1
LEFT JOIN table3 t3 ON t2.id = t3.fkt2
group by t1.sale

SQL query to find comparision between different products

Hi i am a newbie to SQL and have one doubt on comparing different products across multiple tables.
I have 3 tables
T1:
Product_type
order_id
T2 and T3 also has the same fields.
All the tables have different product types. They may or may not have same order ids. Its like you can order product p1 from T1 and product p2 from T2 together on the same order id o1 or they can be separate orders.
I want to find the number of orders where product type(p1) from T1 and product type(p2) from T2 are ordered in the same order(having the same order id).
I am trying to run the query like this :
select COUNT(DISTINCT order_id) as CountOf from
(
select product_type from t1
UNION ALL select product_type from t2
)
AS m
where t1.product_type = p1 and t2.product_type = p2;
What i figured out is that i cannot access t1 and t2 in the outer query since they are used in the inner query. So is there a way i can make comparision between products?
Any help would be greatly appreciated.
Thank you
Try this:
select
count(distinct t1.order_id) as OrderCount
from
t1
inner join
t2 on t1.order_id = t2.order_id
where
t1.product_type = 'p1' and
t2.product_type = 'p2'
I can't understand what you want.
But inner query scope to brackets only. So you can not access outside to brackets. try to this
select COUNT(DISTINCT order_id) as CountOf from
(
select DISTINCT order_id from t1
where t1.product_type = p1
UNION ALL
select DISTINCT order_id from t2
where t2.product_type = p2
) m

Complex MySQL query using group by

Lets say i have two tables
Table1:
product_id, design1, design2
1 A C
2 B A
Table2:
product_id, value
1 10
2 10
Now i want to to sum all the value for particular design for all products.
SELECT designA, SUM(value) FROM (
SELECT b.design1 AS designA, SUM(value) AS value FROM table2 AS a LEFT JOIN table1 AS b ON a.product_id = b.product_id GROUP BY b.design1) AS T GROUP BY designA
It gives me this:
designA SUM(value)
A 10
B 10
Now the problem is that if user has specified design2 in table1 then what ever is the value of design1 will automatically be added in design2. If design2 is not present design1 column then it will be a new row of result:
Desited result is this:
designA SUM(value)
A 20
B 10
C 10
select y.designA, sum(value) from
(select a.design1 as designA, value from
Table1 as a
inner join Table2 as b
on
a.product_id = b.product_id
union all
select a.design2 as designA, value from
Table1 as a
inner join Table2 as b
on
a.product_id = b.product_id) as y
group by y.designA
seems to work for your test data, not tried on other configurations but you should be able to tweak it, if you understand what it's doing.
UNION in the matches based on design2:
SELECT designA, SUM(value) FROM (
SELECT b.design1 AS designA, SUM(value) AS value FROM table2 AS a LEFT JOIN table1 AS b ON a.product_id = b.product_id GROUP BY b.design1
UNION
SELECT b.design2 AS designA, SUM(value) AS value FROM table2 AS a LEFT JOIN table1 AS b ON a.product_id = b.product_id GROUP BY b.design2
) AS T GROUP BY designA

mySQL: Multi-column join on several tables part II

I am adding a 5th table to an existing join. The original query will always return a single row because the where clause specifies a unique ID. Here are the tables we are using:
Table 1
carid, catid, makeid, modelid, caryear
Table 2
makeid, makename
Table 3
modelid, modelname
Table 4
catid, catname
Table 5
id, caryear, makename, modelname
Here is the existing query I am using:
SELECT a.*, e.citympg, e.hwympg
FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
JOIN table5 e on b.makename = e.make
and c.modelname = e.model
and a.caryear = e.year
WHERE a.carid = $carid;
There are 2 issues that I need to solve -
When there is no match on table 5, it does not return any results. It would seem that I need to do some sort of left join or split the query and do a union.
When there is a match on table 5, it returns multiple rows. Since the criteria that would return a single row is not being used, I would settle for an average of citympg and hwympg.
Can both objectives be achieved with a single query? How?
Assuming I understand what you want correctly... This query will constrain the results from table5 to one row per combination of the join criteria, returning average city/hwy mpg.
SELECT a.*, e.citympg, e.hwympg
FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
LEFT JOIN (SELECT year, make, model,
AVG(citympg) as citympg,
AVG(hwympg) as hwympg
FROM table5
GROUP BY year, make, model) e on b.makename = e.make
and c.modelname = e.model
and a.caryear = e.year
WHERE a.carid = $carid;
Note that it will return NULL mpg values when no record in table5 exists.
The usual approach is to use correlated subqueries like this:
SELECT a.*
, (SELECT avg(e.citympg)
FROM table5 e
WHERE e.make = b.makename
AND e.model = c.modelname
AND e.year = a.caryear
) as citympg
, (SELECT avg(e.hwympg)
FROM table5 e
WHERE e.make = b.makename
AND e.model = c.modelname
AND e.year = a.caryear
) as hwympg
FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
WHERE a.carid = $carid