I have this sql tables, and i need to get from all inventory items the newest date from table: orders with the price paid on this date
table:orders
id
date
table:order_items
order_id
inventory_id
price
table:inventory
item_number
if i do something like that:
SELECT inventory.item_number, orders.date, order_items.price
FROM inventory
INNER JOIN order_items ON inventory.id = order_items.inventory_id
INNER JOIN orders ON order_items.order_id = orders.id
WHERE max(orders.date)
it's not working, and i get an error.
What is the correct way to do that
You need a where clause, but the MAX() cannot go there directly. Try a subquery:
SELECT i.item_number, o.date, orders.price
FROM inventory i INNER JOIN
order_items oi
ON i.id = oi.inventory_id INNER JOIN
orders o
ON oi.order_id = o.id
WHERE o.date = (SELECt max(o2.date) FROM orders o2);
Related
I'm trying to query the products not ordered since 01/01/2017 in SSMS.
So far I've come up with a couple of select count queries but have come up empty trying to figure this out. This has 3 tables attached to the query and I need the product names and IDs attached to the query result.
products table columns:
[product_id], [product_name], [brand_id], [category_id], [model_year], [list_price]
orders table columns:
[order_id], [item_id], [product_id], [quantity], [list_price], [discount]
order_items table columns:
[order_id], [customer_id], [order_status], [order_date], [required_date], [shipped_date],[store_id], [staff_id]
SELECT COUNT (*)
FROM production.products
WHERE NOT EXISTS (SELECT 1
FROM sales.orders
JOIN sales.order_items oi ON orders.order_id = oi.order_id
WHERE orders.order_id = oi.order_id
AND orders.order_date > '2017-01-01');
Break it down into three parts
Order items and orders joined in the date range
Products not in #1
WITH prodcuts_in_date_range as
(
SELECT DISTINCT oi.Product_id
FROM Order_items oi INNER JOIN Orders o on o.Order_id = oi.Order_id
WHERE oi.Order_date > '2017-01-01')
)
SELECT * FROM Products p where p.Product_Id not in (SELECT Product_id from
products_in_date_range)
I have two table orders and orderitems.
order table has id,order_total,recieved_amount
orderitems table has id,order_id,name,total_item
I want the sum of recieved_amount, order_total from the order table and sum of total_item from orderitems. so I used
SELECT SUM(`received_amount`) as totalRecieved,
SUM(`order_total`) as orderTotal
FROM `orders` AS `Order`
LEFT JOIN `order_items` AS `OrderItems`
ON (`OrderItems`.`order_id`=`Order`.`id`)
and
SELECT SUM(`received_amount`) as totalRecieved,
SUM(`order_total`) as orderTotal
FROM `orders` AS `Order`
LEFT JOIN `order_items` AS `OrderItems`
ON (`OrderItems`.`order_id`=`Order`.`id`)
group by order.id
but none of them is giving me the correct result.
You are aggregating at two levels of your data hierarchy. This causes a problem with Cartesian products, for each order.
The solution is to aggregate along order_items before doing the join:
SELECT SUM(received_amount) as totalRecieved,
SUM(order_total) as orderTotal
FROM orders o LEFT JOIN
(SELECT oi.order_id, SUM(total_items) as total_items
FROM order_items oi
GROUP BY oi.order_id
) oi
ON oi.order_id = o.id;
As an alternative, you can benefit from cte structure or a temp table like below:
;with cte (order_id, SumTotalItems) as (
SELECT oi.order_id, SUM(total_items) as SumTotalItems
FROM order_items oi
GROUP BY oi.order_id
)
select sum(o.receivedamount) as SumReceivedAmount
, sum(o.order_total) as SumOrderTotal
, cte.SumTotalItems
from orders o
left outer join cte on o.id = cte.order_id
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
;
I was going through an example of LEFT JOIN on w3schools.com.
http://www.w3schools.com/sql/sql_join_left.asp
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
LEFT JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;
The above query will return me all customers with No Orders as NULL Order ID+ All customers having Orders with their Order Ids
How should I modify this query so that it returns All Customers with No Orders + All Customers having Orders with Order date as '1996-09-18'
Thanks in advance.
If you want customers with no orders and those with a specific order date, then you want a WHERE clause:
SELECT c.CustomerName, o.OrderID
FROM Customers c LEFT JOIN
Orders o
ON c.CustomerID = o.CustomerID
WHERE (o.CustomerID is NULL) OR (o.OrderDate = DATE '1996-09-18)
ORDER BY c.CustomerName;
If you wanted all customers with their order on that date (if they have one), then you would move the condition to the ON clause:
SELECT c.CustomerName, o.OrderID
FROM Customers c LEFT JOIN
Orders o
ON c.CustomerID = o.CustomerID AND o.OrderDate = DATE '1996-09-18
ORDER BY c.CustomerName;
Note the difference: the first filters the customers. The second only affects what order gets shown (and NULL will often be shown).
I am trying to find the average dollar amount of an order. I have calculated the average order Total but I need an average that takes into account the fact that not all Orders have a corresponding OrderItems.
This is a homework question and it is as follows:
What is the average $$ value of an order? To get the answer, you need
to add up all the order values and divide this by the
number of orders. There are two possible averages on this question,
because not all of the order numbers in the ORDERS table are in the
ORDERITEMS table... You will calculate and display both averages.
I have writtern the one ignoring orders with no OrderItem, but not sure of how to go about the second case.
SELECT SUM(OrderItems.qty*INVENTORY.price) / COUNT(*) AS dollarValue
FROM Orders, OrderItems, Inventory
WHERE ORDERS.orderid = OrderItems.orderid AND OrderItems.partid = Inventory.partid
Link To DB Diagram
The Avg function will not replace NULL with zero; it will exclude NULL from its calculation. If you have Order rows which have no OrderItem, you need to use Left Joins. A trick you can use in SQL Server is to nest the joins like so (note the parentheses):
Select Avg(OI.Qty * I.Price)
From Orders As O
Left Join (OrderItems As OI
Join Inventory As I
On I.PartId = OI.PartId)
On OI.OrderId = O.OrderId
This will join the Inventory table to the OrderItems table before it Left Joins that result to the Orders table. In this way, OI.Qty and I.Price with both return NULL for Orders that have no OrderItems and be excluded from the calculation. An equivalent approach to the above would be to use two Left Joins:
Select Avg(OI.Qty * I.Price)
From Orders As O
Left Join OrderItems As OI
On OI.OrderId = O.OrderId
Left Join Inventory As I
On I.PartId = OI.PartId
If you wanted to count Orders with no OrderItems as zero, then you need to covert those nulls to zero using Coalesce:
Select Avg(OI.Qty * I.Price) As Avg_ExcludingNull
, Avg( Coalesce(OI.Qty * I.Price,0) ) As Avg_NullAsZero
From Orders As O
Left Join (OrderItems As OI
Join Inventory As I
On I.PartId = OI.PartId)
On OI.OrderId = O.OrderId
SQL has an aggregate function for calculating the average: AVG()
SELECT AVG(OrderItems.qty*INVENTORY.price) AS dollarValue
FROM Orders, OrderItems, Inventory
WHERE ORDERS.orderid = OrderItems.orderid AND OrderItems.partid = Inventory.partid
While we're here, may I suggest you use the more modern JOIN syntax:
SELECT AVG(OrderItems.qty*INVENTORY.price) AS dollarValue
FROM Orders
JOIN OrderItems ON ORDERS.orderid = OrderItems.orderid
JOIN Inventory ON OrderItems.partid = Inventory.partid