Retrieving date an item was ordered on SQL - sql

I have the following tables:
Order (orderID, date, shipID)
Shipping (shipID, price)
PO (prodID, orderID, amount)
Price (prodID, fromDate, price)
I need to retrieve each order ID and the total price including the cost of the items in order + the cost of shipping purchased. The cost of the item has to be the cost of the item on the order date, not the most recent date. The Price table stores the different prices of a product starting at a particular date (fromDate attribute). Hence, the price of a product on day d is the price in the entry with the largest fromDate-value f such that f ≤ d. I understand I can use the command max(fromDate) to retrieve the latest price on an item, however, I cannot figure out how to get the price on a certain date. This is my code so far:
SELECT o.orderId, SUM(pr.price) + SUM(s.price) orderCost
from "Order" o
INNER JOIN Shipping s ON o.shipId = s.shipId
INNER JOIN PO po ON o.orderId = po.orderId
INNER JOIN (SELECT TOP 1 price FROM Price pr WHERE
fromDate = (SELECT MAX(fromDate)FROM Price pr WHERE fromDate <= o."date")) pr
ON pr.prodID = po.prodID
GROUP BY o.orderId;
It gives the following error:
The multi-part identifier "o.date" could not be bound
I am not sure this would quite give me my desired result even if it ran though. Any ideas?

You can first filter the top price on or before your order date using a subquery before joining.
SELECT o.orderId, SUM(pr.price) + SUM(s.price) orderCost
from [Order] o
INNER JOIN Shipping s ON o.shipId = s.shipId
INNER JOIN PO po ON o.orderId = po.orderId
INNER JOIN
(SELECT TOP 1 price, prodID FROM Price pr WHERE
fromDate <= (select max([date]) from [Order])
order by fromDate desc) pr ON pr.prodID = po.prodID
GROUP BY o.orderId;

you rewrite your query like below
SELECT o.orderId, SUM(pr.price+s.price) orderCost
from "Order" o
INNER JOIN Shipping s ON o.shipId = s.shipId
INNER JOIN PO po ON o.orderId = po.orderId
INNER JOIN (SELECT max(fromDate) as fromDate, max(price) as price
,prodID FROM Price pr group by prodID
) pr
ON pr.prodID = po.prodID
where pr.fromDate <= o."date"
GROUP BY o.orderId;

You havn't selected "date" in the first statement that defines "o". Perhaps something like this would work?
with sales as
(
SELECT
o.orderId
, o.date
, SUM(pr.price) + SUM(s.price) orderCost
from "Order" o
INNER JOIN Shipping s ON o.shipId = s.shipId
INNER JOIN PO po ON o.orderId = po.orderId
INNER JOIN (SELECT TOP 1 price FROM Price pr WHERE
fromDate = (SELECT MAX(fromDate)FROM Price pr WHERE fromDate <= o.date)) pr ON pr.prodID = po.prodID
GROUP BY o.orderId, o.date
)
select
orderid
, orderCost
from sales

Related

Join three tables, select only positive amount from second table + first and latest date from third table

I need this result for each Product.
Product ID Date Amount
ID1 10.01.21 3
ID2 15.04.22 2
ID3 NULL NULL
From these 3 Tables
Products Order List Order
ID SKU ProductID OrderID Amount OrderID Date
ID1 ProductA ID1 Order1 -5 Order1 12.03.22
ID2 ProductB ID1 Order2 3 Order2 10.01.21
ID3 ProductC ID2 Order3 2 Order3 15.04.22
For each Product I only want the first positive value from the second table (Order List Table) and the latest and first order Date from table 3 (Order Table).
Following would be wrong even though its the latest, but the amount is -5 (not positive)
ID1, 12.03.22, -5
So far, I got
SELECT
Product.ID,
OrderList.Amount,
Order.Date
FROM
Product
INNER JOIN OrderList ON OrderList.ProductID = Product.ID
INNER JOIN Order ON OrderList.OrderID = Order.ID
I tried several min() or Min distinct, left join etc, but never got any result like this.
If - as mentioned in the comments - you only need a record from orderlist with a positive amount from the most recent order with a positive amount, you can use:
select first 1 p.ID, p.SKU, ol.AMOUNT, o.ORDERDATE
from ORDERS o
inner join ORDERLIST ol on o.ORDERID = ol.ORDERID
inner join PRODUCTS p on p.ID = ol.PRODUCTID
where ol.AMOUNT > 0
order by o.ORDERDATE desc
This will only return a single record, even if that latest order has more than one orderlist record with a positive amount.
If on the other hand you want all orderlist records with a positive amount from the most recent order with positive amount, you can use:
select p.ID, p.SKU, ol.AMOUNT, o.ORDERDATE
from (
select first 1 orders.ORDERID, orders.ORDERDATE
from ORDERS
where exists (
select *
from ORDERLIST
where orderlist.ORDERID = orders.ORDERID and orderlist.AMOUNT > 0)
order by orders.ORDERDATE desc
) o
inner join ORDERLIST ol on o.ORDERID = ol.ORDERID
inner join PRODUCTS p on p.ID = ol.PRODUCTID
where ol.AMOUNT > 0
With the modified requirement specified in the comments:
I actually first need ALL SKU IDs and for each SKU ID one order and
one Items from the order List, but the newest and not negative.
you can do something like this with Firebird 2.5:
with recentproduct as (
select ol.productid, max(o.orderdate) as orderdate
from orders o
inner join orderlist ol on o.orderid = ol.orderid
where ol.amount > 0
group by ol.productid
)
select p.id as productid, p.sku, ol.orderid, ol.amount
from products p
left join (
recentproduct rp
inner join orderlist ol on rp.productid = ol.productid and ol.amount > 0
inner join orders o on o.orderdate = rp.orderdate and o.orderid = ol.orderid
) on p.id = rp.productid
Be aware, this solution is not perfect: if there are multiple orders for the same product on a single date, this will return all of them. This is easier solved in Firebird 3.0 and higher using window functions.

SQL number of products bought by at least 5 unique customers

I have a database with following objects:
Price (prodID, from, price)
Product (prodID, name, quantity)
PO (prodID, orderID, amount)
Order (orderID, date, address, status, trackingNumber, custID, shipID)
Shipping (shipID, company, time, price)
Customer (custID, name)
Address (addrID, custID, address)
I am trying to return the names of products ordered by at least 5 different customers. My code is:
SELECT Product.name, COUNT(DISTINCT custId) as cust_count
FROM Product P
INNER JOIN PO
ON PO.prodId = P.prodId
INNER JOIN "Order" O
ON O.orderId = PO.orderId
INNER JOIN Customer C
ON C.custId = O.custId
HAVING COUNT(DISTINCT custId) > 4;
I am getting the following errors:
The multi-part identifier "Product.name" could not be bound" Ambiguous column name 'custID'
You need a GROUP BY -- and to use your table aliases:
SELECT p.name, COUNT(DISTINCT o.custId) as cust_count
FROM Product P INNER JOIN
PO
ON PO.prodId = P.prodId INNER JOIN
"Order" O
ON O.orderId = PO.orderId
GROUP BY p.name
HAVING COUNT(DISTINCT o.custId) > 4;
Note that the JOIN to Customer is not necessary because the id is in the Order table.
You also try this.I hope this will solve your problem
SELECT DISTINCT TOP (5) o.custId, p.name
FROM Order O INNER JOIN
PO
ON PO.orderID = O.orderID INNER JOIN
Product P
ON P.prodID = PO.prodID

Retrieve cost on certain date SQL

I have the following tables:
Order (orderID, date, shipID)
Shipping (shipID, price)
PO (prodID, orderID, amount)
Price (prodID, fromDate, price)
I need to retrieve each order ID and the total price including the cost of the items in order + the cost of shipping purchased. The cost of the item has to be the cost of the item on the order date, not the most recent date. The Price table stores the different prices of a product starting at a particular date (fromDate attribute). Hence, the price of a product on day d is the price in the entry with the largest fromDate-value f such that f ≤ d. I understand I can use the command max(fromDate) to retrieve the latest price on an item, however, I cannot figure out how to get the price on a certain date. This is my code so far:
SELECT o.orderId, SUM(pr.price) + SUM(s.price) orderCost
FROM "Order" o
INNER JOIN Shipping s
ON o.shipId = s.shipId
INNER JOIN PO po
ON po.orderId = o.orderId
INNER JOIN Price pr
ON pr.prodId = po.prodId
GROUP BY o.orderId;
Try this
select o.orderId, SUM(pr.price) + SUM(s.price) orderCost
from [Order] o
INNER JOIN Shipping s ON o.shipId = s.shipId
inner join PO po on o.shipId = po.shipId
inner join (select top 1 price from Price pr where fromDate = (select max(fromDate)from Price pr where fromDate <= [date])) pr
on pr.prodID = po.prodID
GROUP BY o.orderId;

Finding Customers Last Price Paid

I'm trying to find a way to get customers last price paid the code we have at the moment is:
SELECT Product.ProductCode,
COUNT(Product.ProductCode) AS [Qty Baught],
Product.Description,
Customer.CustomerCode,
Customer.Name,
MAX(OrderHeader.DateTimeCreated) AS [Date],
OrderLine.UnitSellPriceInCurrency AS Sell
FROM Customer
INNER JOIN OrderHeader ON Customer.CustomerID = OrderHeader.CustomerID
INNER JOIN OrderLine ON OrderHeader.OrderID = OrderLine.OrderID
INNER JOIN Product ON OrderLine.ProductID = Product.ProductID
GROUP BY Product.Description,
Product.ProductCode,
Customer.CustomerCode,
Customer.Name,
OrderLine.UnitSellPriceInCurrency
HAVING (Product.ProductCode = 'bcem002')
AND (Customer.CustomerCode = '1000')
ORDER BY MAX(OrderHeader.DateTimeCreated) DESC
This code shows every time the price changed but I only want to see the last price, But the DateCreated and the price paid (UnitSellPriceInCurrency) are on different tables.
Is there a way to Group (UnitSellPriceInCurrency) by (DateCreated) or an alternative way of doing it.
I'm fairly new at this so if there's an obvious way of doing this sorry.
Edit: What i'm getting at the moment with new code, Most of the prices i'm getting up are unrelated to the products
What I want is to get just the last price paid showing but in a way I can change the customer and the product that I'm searching for.
One option might be to use a sub-select utilizing TOP to specify that you only want to retrieve one record, and make sure that it is the "latest" by using the ORDER BY:
SELECT Product.ProductCode,
COUNT(Product.ProductCode) AS [Qty Baught],
Product.Description,
Customer.CustomerCode,
Customer.Name,
MAX(OrderHeader.DateTimeCreated) AS [Date],
(SELECT TOP 1 O.UnitSellPriceInCurrency
FROM OrderLine O
INNER JOIN OrderHeader OH ON O.OrderID = OH.OrderID
WHERE OH.CustomerID = Customer.CustomerID AND O.ProductID = Product.ProductID
ORDER BY OH.DateTimeCreated DESC) AS LatestPrice
FROM Customer
INNER JOIN OrderHeader ON Customer.CustomerID = OrderHeader.CustomerID
INNER JOIN OrderLine ON OrderHeader.OrderID = OrderLine.OrderID
INNER JOIN Product ON OrderLine.ProductID = Product.ProductID
WHERE (Customer.CustomerCode = '1000') AND (Product.ProductCode = 'bcem002')
GROUP BY Product.Description,
Product.ProductCode,
Product.ProductID,
Customer.CustomerCode,
Customer.Name,
Customer.CustomerID
ORDER BY [Date] DESC
In this example LatestPrice will contain the last inserted UnitSellPriceInCurrency for each Customer and product. I'm not sure if the query makes sense with your data (why get only the last price) but it's how I interpreted your request. The query will still return all OrderHeaders though.
Can you please check of this works alright. It would be better if you posted a snapshot of the current result and the expected result you need.
Select
*
FROM
(
SELECT Product.ProductCode,
COUNT(Product.ProductCode) AS [Qty Baught],
Product.Description,
Customer.CustomerCode,
Customer.Name,
OrderHeader.DateTimeCreated AS [Date],
OrderLine.UnitSellPriceInCurrency AS Sell
RANK() OVER (PARTITION BY Customer.CustomerCode,Customer.Name, OrderLine.UnitSellPriceInCurrency ORDER BY OrderHeader.DateTimeCreated) rnk
FROM Customer
INNER JOIN OrderHeader ON Customer.CustomerID = OrderHeader.CustomerID
INNER JOIN OrderLine ON OrderHeader.OrderID = OrderLine.OrderID
INNER JOIN Product ON OrderLine.ProductID = Product.ProductID
WHERE Product.ProductCode = 'bcem002'
AND Customer.CustomerCode = '1000'
GROUP BY Product.Description,
Product.ProductCode,
Customer.CustomerCode,
Customer.Name,
OrderLine.UnitSellPriceInCurrency
) tbl1
WHERE tbl1.rnk =1
;

SQL: list items not sold in between time period

The software we use has two tables for orders, Orders and OrderItems.
I am trying do run a query on the database to show which items have not sold in a period of time.
This is what I have but It's not working ( it brings up all the records)
SELECT
OrderItem.Name,
OrderItem.SKU,
[Order].OrderDate
FROM
[Order]
INNER JOIN OrderItem ON [Order].OrderID = OrderItem.OrderID
WHERE
(OrderItem.SKU NOT IN
(SELECT DISTINCT OrderItem.SKU WHERE ([Order].OrderDate BETWEEN '2014-09-08' AND '2014-01-01')))
You can actually do this with a having clause:
SELECT oi.Name, oi.SKU, max(o.OrderDate) as lastOrderDate
FROM [Order] o INNER JOIN
OrderItem oi
ON o.OrderID = oi.OrderID
GROUP BY oi.Name, oi.SKU
HAVING sum(case when o.OrderDate between '2014-01-01' and '2014-09-08' then 1 else 0 end) = 0;
If you are just looking for orders before this year, it is easier to write the having clause as:
HAVING max(o.OrderDate) < '2014-01-01'
Flip your dates. It should be [Begin Date] Between [End Date]
WHERE (OrderItem.SKU NOT IN
(SELECT DISTINCT OrderItem.SKU
WHERE ([Order].OrderDate BETWEEN '2014-01-01' AND '2014-09-08')))
How about the following:
SELECT oi.Name, oi.SKU, o.OrderDate
FROM [Order] o
INNER JOIN OrderItem oi ON o.OrderID = oi.OrderID
WHERE oi.SKU NOT IN
(
SELECT os.SKU
FROM [Order] os
INNER JOIN OrderItem ois ON os.OrderID = ois.OrderID
WHERE os.OrderDate BETWEEN '2014-01-01' AND '2014-09-08'
)
You have to join to the OrderItem table in the sub query in order to get the SKU.
Looks like your query was build 'upside down'.
SELECT DISTINCT SKU FROM OrderItem oi
WHERE NOT EXISTS
(SELECT 1 FROM Order o
JOIN OrderItem oi2 ON o.OrderID = oi2.OrderID
WHERE oi2.SKU = oi.SKU
AND o.OrderDate BETWEEN '2014-01-01' AND '2014-09-08' );
Ideally, you should have another table containing your distinct items, so you could write the following query to see which items were not sold during a certain period (and may have never been sold at all).
select i.SKU from items
where not exists (
select 1 from OrderItem oi
join Order o on o.OrderID = oi.OrderID
where oi.SKU = i.SKU
and o.OrderDate BETWEEN '2014-01-01' and '2014-09-08'
)
if you don't have such a table, you can select all products that have been ordered at some point, but not during another period
select i.SKU from (
select distinct oi.SKU from OrderItem oi
) i
where not exists (
select 1 from OrderItem oi
join Order o on o.OrderID = oi.OrderID
where oi.SKU = i.SKU
and o.OrderDate BETWEEN '2014-01-01' and '2014-09-08'
)