MYSQL SELECT on two tables with MIN Value - mysql

I have two tables, one is a products table, and the other is an offers table for different vendors offering the same product.
Table1:
sku name
----|-----
a | Iphone
b | Galaxy 5
c | Nexus 6
Table2:
sku price vendor
----|-------|--------
a | 5.00 | storeX
a | 6.00 | storeY
a | 7.00 | storeZ
b | 15.00 | storeP
b | 20.00 | storeQ
b | 30.00 | storeR
c | 11.00 | storeD
c | 12.00 | storeF
c | 13.00 | storeG
I am trying to run a SELECT on these tables so I can get the lowest offer for each item. So my result would be:
sku price vendor
----|--------|--------
a | 5.00 | storeX
b | 15.00 | storeP
c | 11.00 | stored
I have tried SELECT table1.sku,table2.price FROM table2 JOIN table1 ON table2.sku = table1.sku WHERE table2.sku IN ('a','b','c');
But that just give me all offers. Any help with this query is appreciated.

You need two queries: one to determine the min price per product, and then a parent query to select the other fields related to that min price:
SELECT table2.*, table1.name
FROM table2
LEFT JOIN (
SELECT MIN(price) AS min, sku
FROM table2
GROUP BY sku
) AS child ON ((table2.price = child.min) AND (table2.sku = child.sku))
LEFT JOIN table1 ON (table2.sku = table1.sku)
This also has the advantage of showing if multiple stores have the same minimum price.

Related

How to SUM two column in My SQL left join

So i have table Project
---------------------------------
project_id | name|
---------------------------------
1 | project 1 |
2 | project 2 |
---------------------------------
table 02 report
----------------------------------------------------
report_id | report_emp | report_hours |report_project_id|
---------------------------------------------------
1 | 1 | 5 | 1 |
2 | 2 | 7 | 1 |
3 | 1 | 9 | 2 |
4 | 2 | 6 | 1 |
5 | 3 | 8 | 2 |
--------------------------------------------------
and table 03 emp
----------------------------------------------
emp_id | emp_hourly_cost | name |
-----------------------------------------------
1 | 8.5 | A |
2 | 10 | B |
3 | 12 | C |
4 | 9 | D |
5 | 7.5 | D |
-----------------------------------------------
as a final result i wanted to get this table
---------------------------------------------
project | hours | total cost |
---------------------------------------------
1 | 18 | 172.5 |
2 | 17 | 172.5 |
---------------------------------------------
until now i only got the project with total hours but not total cost in this statement
SELECT * from projects left join(select sum(report_hours ) as hours , daily_reports_project_id
from project_id group by report_id)x on x.report_project_id= projects.project_id;
total cost would be sum of all > [total hours of the project of the emp in table 2 * emp_hourly_cost in table 3 ]
i appreciation the help.
Join the tables and aggregate:
SELECT p.project_id project,
SUM(r.report_hours) hours,
SUM(r.report_hours * e.emp_hourly_cost) total_cost
FROM project p
LEFT JOIN report r ON r.report_project_id = p.project_id
LEFT JOIN emp e ON e.emp_id = r.report_emp
GROUP BY project_id;
If there are projects without reports and you want to get 0 instead of NULL as result use also COALESCE():
SELECT p.project_id project,
COALESCE(SUM(r.report_hours), 0) hours,
COALESCE(SUM(r.report_hours * e.emp_hourly_cost), 0) total_cost
FROM project p
LEFT JOIN report r ON r.report_project_id = p.project_id
LEFT JOIN emp e ON e.emp_id = r.report_emp
GROUP BY project_id;
See the demo.
Try this
SELECT sum(column_name1 + column_name2) as 'Total'
This line is selecting the sum of column_name1 and column_name2 from table1, and giving it an alias of 'Total'
FROM table1
This line is specifying that we want data from table1
LEFT JOIN table2
This line is joining table1 with table2 using a LEFT JOIN. This means that all data from table1 will be included, even if there is no matching data in table2
ON table1.column_name1 = table2.column_name2;
This line is specifying the conditions for the join. In this case, it is saying that column_name1 from table1 should match column_name2 from table2
SELECT sum(column_name1 + column_name2) as 'Total'
FROM table1
LEFT JOIN table2
ON table1.column_name1 = table2.column_name2;

LEFT OUTER JOIN with INNER JOIN to Equal Total Rows

I have a Producer and Product table. I'm trying to write 2 queries, Producers that have Products and Producers that don't have Products.
The rows returned from each Query should add up to the total rows in the Producer Table, but this is not the case with my code. The sum of both queries is 819 but there are only 766 rows in the Producer table. Where are the duplicates coming from?
What am I doing wrong with my JOINs?
PRODUCER TABLE
+------+--------+------+------+
| producerID | producerName |
+------+--------+------+------+
| 123 | Toys R Us |
| 234 | GameStop |
| 345 | Amazon |
+------+--------+------+------+
PRODUCT TABLE
+------+--------+------+--------+------+
| productID | productName | producerID |
+------+--------+------+--------+------+
| 1 | Mega Man | 123 |
| 2 | Lemmings | 234 |
| 3 | Mario Kart | 234 |
+------+--------+------+--------+------+
/*STORES CARRYING Products*/
/*This query returns 169*/
SELECT producerName, pt.producerID, productName
FROM Product pt
INNER JOIN Producer pd ON pt.producerID = pd.producerID
/*STORES NOT CARRYING Products*/
/*This query returns 650 */
SELECT producerName, pt.producerID, productName
FROM Producer pd
LEFT OUTER JOIN Product pt ON pt.producerID = pd.producerID
WHERE pt.producerID IS NULL
/*Count all rows returns 766*/
SELECT COUNT(*) FROM Producer
Instead of using a Join, you could use a Subquery.
For example, this query would return all the producers that have a product.
SELECT *
FROM Producer
WHERE producerID IN (SELECT producerID FROM Products)
And this query would return all the producers that do not have a product.
SELECT *
FROM Producer
WHERE producerID NOT IN (SELECT producerID FROM Products)

MySQL - Return Latest Date and Total Sum from two rows in a column for multiple entries

For every ID_Number, there is a bill_date and then two types of bills that happen. I want to return the latest date (max date) for each ID number and then add together the two types of bill amounts. So, based on the table below, it should return:
| 1 | 201604 | 10.00 | |
| 2 | 201701 | 28.00 | |
tbl_charges
+-----------+-----------+-----------+--------+
| ID_Number | Bill_Date | Bill_Type | Amount |
+-----------+-----------+-----------+--------+
| 1 | 201601 | A | 5.00 |
| 1 | 201601 | B | 7.00 |
| 1 | 201604 | A | 4.00 |
| 1 | 201604 | B | 6.00 |
| 2 | 201701 | A | 15.00 |
| 2 | 201701 | B | 13.00 |
+-----------+-----------+-----------+--------+
Then, if possible, I want to be able to do this in a join in another query, using ID_Number as the column for the join. Would that change the query here?
Note: I am initially only wanting to run the query for about 200 distinct ID_Numbers out of about 10 million. I will be adding an 'IN' clause for those IDs. When I do the join for the final product, I will need to know how to get those latest dates out of all the other join possibilities. (ie, how do I get ID_Number 1 to join with 201604 and not 201601?)
I would use NOT EXISTS and GROUP BY
select, t1.id_number, max(t1.bill_date), sum(t1.amount)
from tbl_charges t1
where not exists (
select 1
from tbl_charges t2
where t1.id_number = t2.id_number and
t1.bill_date < t2.bill_date
)
group by t1.id_number
the NOT EXISTS filter out the irrelevant rows and GROUP BY do the sum.
I would be inclined to filter in the where:
select id_number, sum(c.amount)
from tbl_charges c
where c.date = (select max(c2.date)
from tbl_charges c2
where c2.id_number = c.id_number and c2.bill_type = c.bill_type
)
group by id_number;
Or, another fun way is to use in with tuples:
select id_number, sum(c.amount)
from tbl_charges c
where (c.id_number, c.bill_type, c.date) in
(select c2.id_number, c2.bill_type, max(c2.date)
from tbl_charges c2
group by c2.id_number, c2.bill_type
)
group by id_number;

Merging 2 tables with complete

Let say that I have the 2 following tables
id| price id| qty
1 | 1000 1 | 0.5
2 | 1020 3 | 1
3 | 1040 6 | 1.5
4 | 1050
5 | 1070
6 | 1090
And for the result I want to use the last available qty to compute each value
id| price| qty | value (qty * price)
1 | 1000 | 0.5 | 500
2 | 1020 | 0.5 | 510
3 | 1040 | 1 | 1040
4 | 1050 | 1 | 1050
5 | 1070 | 1 | 1070
6 | 1090 | 1.5 | 1635
I can't find a way to do that. Can you help ?
It's just a matter of using a join however you will not get the exact result that you are looking for because you do not have a complete set of values in your second table for the items..
SELECT id, price, qty, qty*price as value from qtys LEFT JOIN prices on id
An INNER JOIN would do just as well.
SELECT id, price, qty, qty*price as value from qtys INNER JOIN prices on id
This will produce something like this:
id| price| qty | value (qty * price)
1 | 1000 | 0.5 | 500
3 | 1040 | 1 | 1040
6 | 1090 | 1.5 | 1635
it's not possible for join on ids 2, 4 and 5. In order to produce the exact output you will have to intrapolate some values for the qty for the missing items. However, you seem to expect 0.5 for some of the missing values and 1.0 for the other.
An SQL JOIN clause is used to combine rows from two or more tables,
based on a common field between them.
The most common type of join is: SQL INNER JOIN (simple join). An SQL
INNER JOIN returns all rows from multiple tables where the join
condition is met.
Source: http://www.w3schools.com/sql/sql_join.asp
You can use a correlated subquery to look up the qty value, then an aggregation:
select id, price, qty, qty * price as value
from (select t1.*,
(select t2.qty
from t2
where t2.id <= t1.id
order by t2.id desc
limit 1
) as qty
from t1
) t;

mySQL largest value by unique entry

I have tried to solve the following problem for the last couple of hours and could not find anything that pointed me in the right direction on Google or Stackoverflow. I believe that this could be a similar problem, but I did not really understand what the author wanted to achieve, hence I am trying it with my own concrete example:
I have a table that basically tracks prices of different products over time:
+------------+--------+----------+
| Product_id | Price | Time |
+------------+--------+----------+
| 1 | 1.30 | 13:00:00 |
| 1 | 1.10 | 13:30:00 |
| 1 | 1.50 | 14:00:00 |
| 1 | 1.60 | 14:30:00 |
| 2 | 2.10 | 13:00:00 |
| 2 | 2.50 | 13:30:00 |
| 2 | 1.90 | 14:00:00 |
| 2 | 2.00 | 14:30:00 |
| 3 | 1.45 | 13:00:00 |
| 3 | 1.15 | 13:30:00 |
| 3 | 1.50 | 14:00:00 |
| 3 | 1.55 | 14:30:00 |
+------------+--------+----------+
I would now like to query the table so that the rows with max. Price for each product are returned:
+------------+--------+----------+
| Product_id | Price | Time |
+------------+--------+----------+
| 1 | 1.60 | 14:30:00 |
| 2 | 2.50 | 13:30:00 |
| 3 | 1.55 | 14:30:00 |
+------------+--------+----------+
Also, in case of duplicates, i.e. if there is a max. Price at two different points in time, it should only return one row, preferably the one with the smallest value of time.
I have tried MAX() and GREATEST(), but could not achieve the desired outcome to show the wanted values for each product. Efficiency of the query is not the most important factor, but I have about 500 different products with several million rows of data, hence splitting the table by unique product did not seem like an appropriate solution.
Group the data product id and pick the max price and max time
select t1.product_id,t1.price,min(t1.time) as time from your_table t1
inner join (
select Product_id,max(price)as price from
your_table group by Product_id
) t2 on t1.Product_id=t2.Product_id and t1.price=t2.price group by t1.product_id
Sql Fiddle Example:
http://sqlfiddle.com/#!9/020c3/9
http://sqlfiddle.com/#!9/020c3/1
SELECT p.*
FROM prices p
LEFT JOIN prices p1
ON p.product_id = p1.product_id
AND p.time<p1.time
WHERE p1.product_id IS NULL
If you need maximum price to get you can:
http://sqlfiddle.com/#!9/020c3/6
SELECT p.*
FROM prices p
LEFt JOIN prices p1
ON p.product_id = p1.product_id
AND p.price<p1.price
WHERE p1.product_id IS NULL;
And the last approach since I didn't get the goal from the beggining:
http://sqlfiddle.com/#!9/ace04/2
SELECT p.*
FROM prices p
LEFt JOIN prices p1
ON p.product_id = p1.product_id
AND (
p.price<p1.price
OR (p.price=p1.price AND p.time<p1.time)
)
WHERE p1.product_id IS NULL;
This solution is assuming the existence of an additional my_table.id column that needs to be used in case there are duplicate values for (Product_id, price, time) in your table. id is assumed to be a unique value in the table.
SELECT *
FROM my_table t1
WHERE NOT EXISTS (
SELECT *
FROM my_table t2
WHERE t1.Product_id = t2.Product_id
AND ((t1.price < t2.price) OR
(t1.price = t2.price AND t1.time > t2.time) OR
(t1.price = t2.price AND t1.time = t2.time AND t1.id > t2.id))
)
Alternatively, the predicate on price and time could also be expressed using a row value expression predicate (not sure if it's more readable, as t1 and t2 columns are mixed in a each row value expression):
SELECT *
FROM my_table t1
WHERE NOT EXISTS (
SELECT *
FROM my_table t2
WHERE t1.Product_id = t2.Product_id
AND (t1.price, t2.time, t2.id) < (t2.price, t1.time, t1.id)
)