Joining multiple select sql statements (4 tables) - mysql

I need to join together 2 SQL statements and both of those statements work on their own. But I don't know how to combine both into 1 SQL statement.
I have two tables in 1st statement, TR120 and TR1201.
The SQL is this:
select
PRODUCT, PRICE, QUANTITY, INVOICE.DATE
from
TR1201
left join
(select
DATE, ID as INVOICE_ID, INVOICE
from TR120) as INVOICE on INVOICE.INVOICE_ID = ID
where
INVOICE.DATE >= '2016-06-01' and INVOICE.DATE <= '2016-06-30'
This returns a list of all the products I sold, with price, quantity and date of sales in a specific time frame from 01-06-16 till 30-06-16.
Now I need to find out the latest price that I bought product for in different two tables TR100 and TR1001 based on the product and date of sale from the 1st SQL statement.
select
PRODUCT, PRICE, SUP.DATE
from
TR1001
left join
(select
DATE, ID as SUP_ID, SUP_INVOICE
from TR100) as SUP on SUP.SUP_ID = ID
This returns a list of all the products that I have bought with a price and a date. I only need last record from this query based on product and date of purchased.
TR120
ID | INVOICE | DATE
1 | 000001 |2016-06-05
2 | 000002 |2016-06-15
3 | 000003 |2016-06-25
TR1201
ID | PRODUCT | PRICE A | QUANTITY
1 | A | 2,00 | 5
2 | A | 2,00 | 2
3 | A | 2,00 | 1
TR100
ID | SUP_INVOICE | DATE
1 | 160001 | 2016-05-30
2 | 160002 | 2016-06-16
TR1001
ID | PRODUCT | PRICE B
1 | A | 0,5
2 | A | 0,7
The result I am trying to get is this:
PRODUCT | PRICE A (tr1201) | QUANTITY | DATE (tr100) | PRICE B (tr1001)
A | 2 | 5 | 2016-05-30 | 0,5
A | 2 | 2 | 2016-05-15 | 0,5
A | 2 | 1 | 2016-05-16 | 0,7
That is all I want to do :(

Have you tried first_value?
FIRST_VALUE ( [scalar_expression ] )
OVER ( [ partition_by_clause ] order_by_clause [ rows_range_clause ] )
it works like this:
select distinct id,
first_value(price) over (partition by id (,sup) order by date DESC (latest, ASC for oldest)) as last_price
from table;
Documentation can be found here: https://msdn.microsoft.com/en-us/library/hh213018.aspx

I don't have your tables so cannot test and therefore am providing advice only.
I think what you need is an Outer apply like this instead of joins
select
T1.Product
, T1.Price
, T2.DATE -- Alias this
, T2.Price -- Alias this
, T3.DATE -- Alias this
, T3.Price -- Alias this
from T1
OUTER APPLY (
select top 1
Date
,Price
from table2
WHERE ID = T1.Id AND product = T1.Product-- plus any other joins
ORDER BY Date desc
) as T2
OUTER APPLY (
select top 1
Date
,Price
from table3
WHERE ID = T1.Id AND product = T1.Product-- plus any other joins
ORDER BY Date desc
) as T3

Related

Calculate date difference from previous row of each unique ID in MySQL

I am a SQL beginner and am learning the ropes of querying. I'm trying to find the date difference between purchases by the same customer. I have a dataset that looks like this:
ID | Purchase_Date
==================
1 | 08/10/2017
------------------
1 | 08/11/2017
------------------
1 | 08/17/2017
------------------
2 | 08/09/2017
------------------
3 | 08/08/2017
------------------
3 | 08/10/2017
I want to have a column that shows the difference in days for each unique customer purchase, so that the output will look like this:
ID | Purchase_Date | Difference
===============================
1 | 08/10/2017 | NULL
-------------------------------
1 | 08/11/2017 | 1
-------------------------------
1 | 08/17/2017 | 6
-------------------------------
2 | 08/09/2017 | NULL
-------------------------------
3 | 08/08/2017 | NULL
-------------------------------
3 | 08/10/2017 | 2
What would be the best way to go about this using a MySQL query?
Not so hard, just use a subquery to find previous purchase for each existing purchase for the customer, and self-join to that record.
Select t.id, t.PurchaseDate, p.Purchase_date,
DATEDIFF(t.PurchaseDate, p.Purchase_date) Difference
From myTable t -- t for This purchase record
left join myTable p -- p for Previous purchase record
on p.id = t.Id
and p.purchase_date =
(Select Max(purchase_date)
from mytable
where id = t.id
and purchase_date <
t.purchaseDate)
This is rather tricky in MySQL. Probably the best way to learn if you are a beginning is the correlated subquery method:
select t.*, datediff(purchase_date, prev_purchase_date) as diff
from (select t.*,
(select t2.purchase_date
from t t2
where t2.id = t.id and
t2.purchase_date < t.purchase_date
order by t2.purchase_date desc
limit 1
) as prev_purchase_date
from t
) t;
Performance should be okay if you have an index on (id, purchase_date).
It is possible to solve it not using dependent subquery
SELECT yt.id, create_date, NULLIF(yt.create_date - tm.min_create_date, 0)
FROM your_table yt
JOIN
(
SELECT id, MIN(create_date) min_create_date
FROM your_table
GROUP BY id
) tm ON tm.id = yt.id
sqlfiddle demo

MySQL SUM over a virtual subquery field (with another SUM) with GROUP BY

I have two tables: invoices and items.
invoices
id | timest
items
id | invoice_id | price | qty
It is apparent an invoice may have several items - items.invoice_id = invoices.id.
I have the following query that selects all invoices with the total sum of theirs items:
SELECT id, DATE_FORMAT(FROM_UNIXTIME(inv.time), "%Y-%m" ) AS _period,
(SELECT SUM(it.price*it.quantity) FROM items AS it WHERE it.invoice_id=inv.id) as total
FROM `invoices` `inv`
This generates something like:
id| _period | total
-------------------
1 | 2014-06 | 100
4 | 2014-06 | 200
5 | 2014-07 | 660
6 | 2014-07 | 300
7 | 2014-07 | 30
9 | 2015-02 | 225
Now I want to group it by the period to have output as:
_period | qty | total_price
---------------------------
2014-06 | 2 | 300
2014-07 | 3 | 990
2015-02 | 1 | 224
I can easily do it for the quantity field as
SELECT DATE_FORMAT(FROM_UNIXTIME(inv.time), "%Y-%m" ) AS _period,
COUNT(inv.id) as qty
FROM `invoices` `inv`
GROUP BY _period
But I can't figure out how the similar thing could be done for the total_price field, which results from a subquery virtual field? Does anyone have any idea?
Thank you!
You should do this using a LEFT JOIN and GROUP BY:
SELECT DATE_FORMAT(FROM_UNIXTIME(i.time, '%Y-%m') AS _period,
COUNT(DISTINCT i.id) as num_invoices
SUM(i.price * it.quantity) as total
FROM invoices i LEFT JOIN
items it
ON it.invoice_id = i.id
GROUP BY _period
ORDER BY _period;
try this
SELECT InnerTable._period, Count(InnerTable.id) as id, Sum(InnerTable.total) as total FROM
(SELECT id, DATE_FORMAT(FROM_UNIXTIME(inv.time), "%Y-%m" ) AS _period,
(SELECT SUM(it.price*it.quantity) FROM items AS it WHERE it.invoice_id=inv.id) as total
FROM `invoices` `inv`) as InnerTable FROM GROUP BY InnerTable._period.
Making sub table from the query and then put group by on it.

How can I identify if a certain row is the last by using an ID in MySQL

Sorry to confuse you about my title. I am building an auction system and I am having a difficulty in getting the user's winning item.
Example I have a table like this:
the columns are:
id, product_id, user_id, status, is_winner, info, bidding_price, bidding_date
here's my sql fiddle:
http://sqlfiddle.com/#!9/7097d/1
I want to get every user's item that they already win. So I need to identify if they are the last who bid in that item.
I need to filter it using a user_id.
If I do a query like this:
SELECT MAX(product_id) AS product_id FROM auction_product_bidding
WHERE user_id = 3;
it will get only the product_id that is 12 and the product_id of 9 did not get. Product ID 9 is also that last bid of the user_id 3.
Can you help me? I hope you got my point. Thanks. Sorry if my question a little bit confusing.
According to your question, seems 11 is also what you want, try this query:
SELECT apd.product_id
FROM auction_product_bidding apd
JOIN (
SELECT MAX(bidding_date) AS bidding_date, product_id
FROM auction_product_bidding
GROUP BY product_id
) t
ON apd.product_id = t.product_id
AND apd.bidding_date = t.bidding_date
WHERE apd.user_id = 3;
Check Demo Here
select id,product_id,user_id,status,is_winner,info,bidding_price,bidding_date,rank
from
( SELECT apb.*,
greatest(#rank:=if(product_id=#prodGrp,#rank+1,1),-1) as rank,
#prodGrp:=product_id as dummy
FROM auction_product_bidding apb
cross join (select #prodGrp:=-1,#rank:=0) xParams
order by product_id,bidding_date DESC
) xDerived
where user_id=3 and rank=1;
That user won 9,11,12
+----+------------+---------+--------+-----------+------+---------------+---------------------+------+
| id | product_id | user_id | status | is_winner | info | bidding_price | bidding_date | rank |
+----+------------+---------+--------+-----------+------+---------------+---------------------+------+
| 60 | 9 | 3 | | 0 | | 75000.00 | 2016-08-02 16:31:23 | 1 |
| 59 | 11 | 3 | | 0 | | 15000.00 | 2016-08-02 12:04:16 | 1 |
| 68 | 12 | 3 | | 0 | | 18000.00 | 2016-08-10 09:20:01 | 1 |
+----+------------+---------+--------+-----------+------+---------------+---------------------+------+
SELECT product_id FROM auction_product_bidding where bidding_price= any
(select max(bidding_price) from auction_product_bidding group by product_id)
and user_id='3';
select * from
(select product_id,user_id,max(bidding_price) from
(select * from auction_product_bidding order by bidding_price desc) a
group by product_id) b
where user_id=3;
Answer:
product_id user_id max(bidding_price)
9 3 75000
11 3 15000
12 3 18000
An idea could be to sort the table desc by date and select every distinct row by product_id and customer_id. Something like
SELECT DISTINCT prod_id, user_id FROM (
SELECT * FROM auction_product_bidding ORDER BY date DESC
)
You want everything that bids last in 3, is it right ?

LEFT JOIN to newest row

I'm trying to get data from one table with additional data from second, but in second table i have many records connected to records in first table and I want take newest.
In first table i keep products and i second i keep prices with data. I want take products with actual(newest) price.
Products table:
ID | NAME
---+----------
1 | "jacket"
2 | "pants"
Prices table:
ID | PRODUCT_ID | DATE | PRICE
---+------------+------------+-------
1 | 1 | 2015-05-12 | 200
2 | 1 | 2015-07-12 | 100
3 | 2 | 2015-03-12 | 60
4 | 2 | 2015-08-12 | 90
Expected result:
1, "jacket", 100
2, "pants", 90
How can I do this?
Actually i've found solution - but with 2 subqueries. Doesn't look so good.
Find the max date for each price and then inner join with the rest of the tables.
SQL Fiddle
SELECT aa.id, aa.name, bb.price
FROM products AS aa
INNER JOIN prices AS bb
ON aa.id = bb.product_id
INNER JOIN (
SELECT product_id, MAX(date) AS max_date
FROM prices AS cc
GROUP BY product_id
) AS _aa
ON aa.id = _aa.product_id
WHERE bb.date = _aa.max_date;

Select and summarize data from three tables

i have three tables
customer
id | name
1 | john
orders
id | customer_id | date
1 | 1 | 2013-01-01
2 | 1 | 2013-02-01
3 | 2 | 2013-03-01
order_details
id | order_id | qty | cost
1 | 1 | 2 | 10
2 | 1 | 5 | 10
3 | 2 | 2 | 10
4 | 2 | 2 | 15
5 | 3 | 3 | 15
6 | 3 | 3 | 15
i need to select data so i can get the output for each order_id the summary of the order
sample output. I will query the database with a specific customer id
output
date | amount | qty | order_id
2013-01-01 | 70 | 7 | 1
2013-02-01 | 50 | 4 | 2
this is what i tried
SELECT
orders.id, orders.date,
SUM(order_details.qty * order_details.cost) AS amount,
SUM(order_details.qty) AS qty
FROM orders
LEFT OUTER JOIN order_details ON order_details.order_id=orders.id AND orders.customer_id = 1
GROUP BY orders.date
but this returns the same rows for all customers, only that the qty and cost dont hav values
Maybe
SELECT
orders.id, orders.date,
SUM(order_details.qty * order_details.cost) AS amount,
SUM(order_details.qty) AS qty
FROM orders
LEFT JOIN order_details ON order_details.order_id=orders.id
AND orders.customer_id = 1
GROUP BY orders.date
HAVING amount is not null AND qty is not null
SQL Fiddle
NOTE: In the following query, it is assumed that the dates are stored in the database as a string in the format specified in the OP. If they are actually stored as some type of date with time then you'll want to modify this query such that the time is truncated from the date so the date represents the whole day. You can use the date or date_format functions. But then you'll need to make sure that you modify the query appropriately so the group by and select clauses still work. I added this modification as comments inside the query.
select
o.date -- or date(o.date) as date
, sum(odtc.total_cost) as amount
, sum(odtc.qty) as qty
, o.order_id
from
orders o
inner join (
select
od.id
, od.order_id
, od.qty
, od.qty * od.cost as total_cost
from
order_details od
inner join orders _o on _o.id = od.order_id
where
_o.customer_id = :customer_id
group by
od.id
, od.order_id
, od.qty
, od.cost
) odtc on odtc.order_id = o.id
where
o.customer_id = :customer_id
group by
o.date -- or date(o.date)
, o.order_id
;
I don't think you want an outer join just a simple inner join on all 3 tables:
FROM orders, order_details, customer
WHERE orders.customer_id=customer.id
AND order_details.order_id=orders.id