How can I select lastest purchase price before a selling date? - sql

I have 5 tables in my database, products, purchase_orders, invoice, invoice_details, and product_prices and their schema are like below.
Table: products
id
trade_name
Table: purchase_orders
id
product_id
created
Table: invoices
id
created
Table invoice_details
id
invoice_id
product_id
price_id
Table product_prices
id
retail_price
effective_from
effective_to
I think that I need to somehow join or check created on purchase_orders to created on invoices. So, I started with getting drug id, invoice date.
select d.id as drug_id
, i.created as invoice_created
, dp.retail_price
from drugs d
inner join invoice_details id
on d.id = id.drug_id
inner join invoices i
on i.id = id.invoice_id
inner join drug_prices dp
on dp.id = id.price_id
The next step is to match created on invoice that I have to created on purchase_orders which I haven't figured it out.
inner join (
select drug_id
, purchase_price
, ISNULL(created, CONVERT(DATETIME, '2015-10-07 01:37:12.370')) as created
from purchase_orders po
) as prepared_po
on prepared_po.created <= i.created
How can I get the lasted purchase price for each item that I sold?

Here's a simplified version of the logic you need (I renamed your columns so that it's easier to see which are which without doing all the intermediary joins you've already written yourself):
;With CTE as (select a.productID, a.saledate, b.price, b.purchasedate
, row_number() over (partition by a.productID, a.saledate
order by b.purchasedate desc) RN
from sales a
left join purchases b
on a.productID = b.productID and a.saledate >= b.purchasedate
)
Select productID, saledate, price, purchasedate
from CTE where RN = 1
Basically, you join to get all purchase records up to the sale date, then use row_number to find the latest one.
http://sqlfiddle.com/#!6/a0f68/2/0

Related

Use 1 SQL query to join 3 tables and find the category of products that generates the most revenue for each customer segment

I am using SQLite3 for this following query.
I have a table called "products" that looks like this:
I have a table called "transactions" that looks like this:
I have a table called "segments" that looks like this:
For each active segment, I want to find the category that produces the highest revenue.
I think that I know how to do this in 3 different queries.
create table table1 as
SELECT s.seg_name, p.category, t.item_qty * t.item_price as revenue
from segments s
JOIN
transactions t
on s.cust_id = t.cust_id
JOIN products p
on p.prod_id = t.prod_id
where s.active_flag = 'Y'
order by s.seg_name, p.category
;
create table table2 as
select seg_name, category, sum(revenue) as revenue
from table1
group by seg_name, category;
select seg_name, category, max(revenue) as revenue
from table2
group by seg_name;
How can I do it in 1 query?
here is one way :
select seg_name,category,revenue
from (
select
s.seg_name,
p.category,
sum(t.item_qty * t.item_price) as revenue,
rank() over (partition by seg_name order by sum(t.item_qty * t.item_price) desc) rn
from segments s
join transactions t on s.cust_id = t.cust_id
join products p on p.prod_id = t.prod_id
where s.active_flag = 'Y'
group by seg_name, p.category
) t where rn = 1

SQL NESTED JOIN NOT USING WHERE

What is the current price of each product? Display product code, product description, unit, and its current price. Always assume that NOT ALL products HAVE unit price BUT you need to display it even if it has no unit price on it. without using WHERE script
Product Table
prodCode
description
unit
PriceHist Table
prodCode
effDate
unitPrice
This is my work... Please Help me to improve my anwswer.
SELECT p.prodCode, p.description, p.unit, MAX(ph.unitPrice) "Current Price"
FROM product p
INNER JOIN priceHist AS ph
ON p.prodCode = ph.prodCode
GROUP BY p.prodCode, p.description, p.unit
ORDER BY MAX(ph.unitPrice);
Someone said I NEED TO USE PRICEHIST TWICE
User window functions and left join:
select . . . -- whatever columns you want
from products p left join
(select ph.*,
row_number() over (partition by p.prodcode order by effdate desc) as seqnum
from pricehist ph
) ph
on ph.prodcode = p.prodcode and ph.seqnum = 1;
Try this:
SELECT a.prodCode, a.description, a.unit, SUM(b.unitPrice)
FROM ProductTable a
LEFT JOIN PriceHistTable b ON a.prodCode = b.prodCode
GROUP BY a.prodCode, a.description, a.unit, b.unitPrice
Assuming you want to select unitPrice for prodCode with latest effDate, below query should work. Explanation in comments.
select x.prodCode, x.description, x.unit, y.unitPrice
from Product x
left join (
--- Create a table y with one row per (prodCode, effDate)
--- choosing the latest effDate per prodCode
select a.prodCode, a.effDate, a.unitPrice
from PriceHist a
join (
--- Create b as (prodCode, effDate)
select prodCode, max(effDate) as maxEffDate
from PriceHist
group by prodCode
) b
on a.prodCode = b.prodCode and a.effDate = b.maxEffDate
) y
on x.prodCode = y.prodCode

Query giving all the record need to generate latest record from history table

Need to get latest record from history table while joining with table.
when I am doing query with below
select * from Product, ProductHistory where Product.ProductNo=ProductNo.ProductNo
It gives all the record what I need is latest record from ProductHistory table
untested
Here's how I would do it:
start with a subquery to get the "latest" date for each Product:
select ProductNo, max(Date)
from ProductHistory
group by ProductNo
Then you have to join that result to the ProductHistory table to get the corresponding "Transaction":
select PH.ProductNo, PH.Transaction, PH.Date
from (
select ProductNo, max(Date)
from ProductHistory
group by ProductNo
) MaxPH
inner join ProductHistory PH
on PH.ProductNo = MaxPH.ProductNo
and PH.Date = MaxPH.Date
Finally, join the Product table to get the Product (name)
select P.Product, P.ProductNo, PH.Transaction, PH.Date
from (
select ProductNo, max(Date)
from ProductHistory
group by ProductNo
) MaxPH
inner join ProductHistory PH
on PH.ProductNo = MaxPH.ProductNo
and PH.Date = MaxPH.Date
inner join Product P on P.ProductNo = PH.ProductNo
You could also use row numbers with a partition to find the "lastest".

Join two tables but only get most recent associated record

I am having a hard time constructing an sql query that gets all the associated data with respect to another (associated) table and loops over into that set of data on which are considered as latest (or most recent).
The image below describes my two tables (Inventory and Sales), the Inventory table contains all the item and the Sales table contains all the transaction records. The Inventory.Id is related to Sales.Inventory_Id. And the Wanted result is the output that I am trying to work on to.
My objective is to associate all the sales record with respect to inventory but only get the most recent transaction for each item.
Using a plain join (left, right or inner) doesn't produce the result that I am looking into for I don't know how to add another category in which you can filter the most recent data to join to. Is this doable or should I change my table schema?
Thanks.
You can use APPLY
Select Item,Sales.Price
From Inventory I
Cross Apply(Select top 1 Price
From Sales S
Where I.id = S.Inventory_Id
Order By Date Desc) as Sales
WITH Sales_Latest AS (
SELECT *,
MAX(Date) OVER(PARTITION BY Inventory_Id) Latest_Date
FROM Sales
)
SELECT i.Item, s.Price
FROM Inventory i
INNER JOIN Sales_Latest s ON (i.Id = s.Inventory_Id)
WHERE s.Date = s.Latest_Date
Think carefully about what results you expect if there are two prices in Sales for the same date.
I would just use a correlated subquery:
select Item, Price
from Inventory i
inner join Sales s
on i.id = s.Inventory_Id
and s.Date = (select max(Date) from Sales where Inventory_Id = i.id)
select * from
(
select i.name,
row_number() over (partition by i.id order by s.date desc) as rownum,
s.price,
s.date
from inventory i
left join sales s on i.id = s.inventory_id
) tmp
where rownum = 1
SQLFiddle demo

Last order item in Oracle SQL

I need to list columns from customer table, the date from first order and all data from last one, in a 1:N relationship between customer and order tables. I'm using Oracle 10g.
How the best way to do that?
TABLE CUSTOMER
---------------
id NUMBER
name VARCHAR2(200)
subscribe_date DATE
TABLE ORDER
---------------
id NUMBER
id_order NUMBER
purchase_date DATE
purchase_value NUMBER
Here is one way of doing it, using the row_number function, one join, and on aggregation:
select c.*,
min(o.purchase_date) as FirstPurchaseDate,
min(case when seqnum = 1 then o.id_order end) as Last_IdOrder,
min(case when seqnum = 1 then o.purchase_date end) as Last_PurchaseDate,
min(case when seqnum = 1 then o.purchase_value end) as Last_PurchaseValue
from Customer c join
(select o.*,
row_number() over (partition by o.id order by purchase_date desc) as seqnum
from orders o
) o
on c.customer_id = o.order_id
group by c.customer_id, c.name, c.subscribe_date
It's not obvious how to join the customer table to the orders table (order is a reserved word in Oracle so your table can't be named order). If we assume that the id_order in orders joins to the id in customer
SELECT c.id customer_id,
c.name name,
c.subscribe_date,
o.first_purchase_date,
o.id last_order_id,
o.purchase_date last_order_purchase_date,
o.purchase_value last_order_purchase_value
FROM customer c
JOIN (SELECT o.*,
min(o.purchase_date) over (partition by id_order) first_purchase_date,
rank() over (partition by id_order order by purchase_date desc) rnk
FROM orders o) o ON (c.id = o.id_order)
WHERE rnk = 1
I'm confused by your field names, but I'm going to assume that ORDER.id is the id in the CUSTOMER table.
The earliest order date is easy.
select CUSTOMER.*, min(ORDER.purchase_date)
from CUSTOMER
inner join ORDER on CUSTOMER.id = ORDER.id
group by CUSTOMER.*
To get the last order data, join this to the ORDER table again.
select CUSTOMER.*, min(ORD_FIRST.purchase_date), ORD_LAST.*
from CUSTOMER
inner join ORDER ORD_FIRST on CUSTOMER.id = ORD_FIRST.id
inner join ORDER ORD_LAST on CUSTOMER.id = ORD_LAST.id
group by CUSTOMER.*, ORD_LAST.*
having ORD_LAST.purchase_date = max(ORD_FIRST.purchase_date)
Maybe something like this assuming the ID field in the Order table is actually the Customer ID:
SELECT C.*, O1.*, O2.purchase_Date as FirstPurchaseDate
FROM Customer C
LEFT JOIN
(
SELECT Max(purchase_date) as pdate, id
FROM Orders
GROUP BY id
) MaxPurchaseOrder
ON C.Id = MaxPurchaseOrder.Id
LEFT JOIN Orders O1
ON MaxPurchaseOrder.pdate = O1.purchase_date
AND MaxPurchaseOrder.id = O1.id
LEFT JOIN
(
SELECT Min(purchase_date) as pdate, id
FROM Orders
GROUP BY id
) MinPurchaseOrder
ON C.Id = MinPurchaseOrder.Id
LEFT JOIN Orders O2
ON MinPurchaseOrder.pdate = O2.purchase_date
AND MinPurchaseOrder.id = O2.id
And the sql fiddle.