SQL-Server, confront Customers with Employees function - sql

I might have a really simple question, but it doesn't seem i can find the solution yet. Basically, i have to write a SQL-Server function, based on Northwind DB. It has to:
Take 2 dates as arguments and display, without repetition these Customer's data ID | Name | City | Address , for those customers where the total purchase he had made from at least one Employee , is greater than the average sale made by this Employee between the two dates.
So the main steps should be:
1. Retrieve the total purchase made from a Customer from each Employee. I know how to get the total purchase from each Company:
SELECT
Customers.CompanyName, SUM(UnitPrice*Quantity)
FROM Orders inner join [Order Details]
ON Orders.OrderID=[Order Details].OrderID INNER JOIN
Customers ON Orders.CustomerID=Customers.CustomerID
GROUP BY Customers.CompanyName
But how can i get those made from each employee?
2.Confront this with the average sales of this Employee between the given dates. I can get the average for each employee:
SELECT FirstName+' '+LastName, AVG(UnitPrice*Quantity)
FROM Orders inner join [Order Details]
ON Orders.OrderID=[Order Details].OrderID
INNER JOIN Employees
ON Orders.EmployeeID=Employees.EmployeeID
WHERE OrderDate BETWEEN #dt1 and #dt2
GROUP BY FirstName+' '+LastName
Note that i'm only pasting the query part, but here, the Employee should depend on the first query (probably this should be put inside a subquery)
Everything should be put inside a single function (it should not be split in two). The Northwind DB diagram is: Northwind Diagram . Please help!

Hope I got the logic right:
create function x (#from datetime, #to datetime)
returns table
as
return (
with cust as (
select o.customerid, o.employeeid, sum(unitprice*quantity) as cust_purchase
from orders o
inner join [order details] d on o.orderid=d.orderid
where o.orderdate between #from and #to
group by o.customerid, o.employeeid
),
emp as (
select o.employeeid, avg(unitprice*quantity) as emp_sale
from orders o
inner join [order details] d on o.orderid=d.orderid
where o.orderdate between #from and #to
group by o.employeeid
)
select c.customerid, c.companyname, c.city, c.address
from cust
inner join emp on cust.employeeid = emp.employeeid
and cust.cust_purchase > emp.emp_sale
inner join customers c on cust.customerid = c.customerid
)
go
select * from x ('19980401', '19980430')

Related

SQL Subqueries - Exists – Any - All

I have a problem facing this subquery SQL exercice,using Northwind DB:
**16.
From order number 10251 show employee's name,company's name, order's
date,name of each product,quantity,unit price and
final price (= unitprice * quantity – unitprice*quantity*discount)
**
The following is my attempt of a solution, each of the subqueries work fine by their own,giving the expected result but it fails when combined together in the same query
select
(select FirstName from Employees where EmployeeID=Orders.EmployeeID)as 'Name',
(select Customers.CompanyName from Customers where Customers.CustomerID = Orders.CustomerID)'Company name' ,
(select Products.ProductName,Products.UnitPrice,
[Order Details].Quantity,
(Products.UnitPrice*[Order Details].Quantity-Products.UnitPrice*[Order Details].Quantity*[Order Details].Discount)
AS 'Final Price' from Products
INNER JOIN [Order Details] on Products.ProductID= [Order Details].ProductID
WHERE [Order Details].OrderID=10251),
Orders.OrderDate
from Orders
where OrderID=10251
I believe your query was failing because the third subquery (for Final Price) was returning a relation, as opposed to a scalar value.
I've re-written the query in a form that opts for joins rather than subqueries. Subqueries can be useful but I think using joins here makes the query little easier to read and work with.
select firstName as Name,
C.companyName as CompanyName,
P.UnitPrice * OD.Quantity
- (P.UnitPrice * OD.Quantity * OD.Discount)
as FinalPrice
from Orders as O
left join Employees as E
on E.employeeId = O.employeeId
left join Customers as C
on C.customerId = O.customerId
left join [Order Details] as OD
on OD.orderId = O.orderId
left join Products as P
on P.productId = OD.produtId

Query returning individuals most recent order, date of the order, number of products in the order and the total amount

Need help with a query to returns each individuals most recent order, date of the order, number of products in the order and the total amount. I am kind of stuck trying to get the number of products and total.
Here are the table diagrams
Not sure if I should be using multiple joins or subqueries:
SELECT FirstName, LastName, MAX(O.OrderDate), O.OrderDate
FROM Customer C
INNER JOIN Order O ON C.CustomerID = O.CustomerID
It is always good practice to start from assumed dim tables such as product.This Query should help. It is better to aggregate quantity and amount to get results at aggregate level
SELECT FirstName
,LastName
,max(o.orderdate) Orderdate
,Sum(Quantity) Quantity
,Sum(TotalAmount) TotalAmount
FROM Product p
INNER JOIN Orderitem oi
ON Oi.product_id = p.id
INNER JOIN
ORDER o
ON o.id = oi.order_id
INNER JOIN Customer c
ON c.id = o.Customer_id
GROUP BY FirstName
,LastName
not sure if you want aggregations but here you go:
SELECT customer.firstname, customer.lastname, COUNT(DISTINCT orderitem.productid), [order].totalamount
FROM [order] LEFT JOIN customer ON [order].customerid=customer.id LEFT JOIN orderitem ON order.id=orderitem.orderid
WHERE [order].date=MAX([order].date)
GROUP BY customer.firstname,customer.lastname, [order].totalamount
Still don't know why you are applying a where clause for the last order, it's up to you to keep or not the where condtion.

sql use aggregate function that counts a unique value with group by using inner joins

I searched and found similar questions online but not my particular one, they all use where or having clause.If theres one similar to mine please link it. It's a 2 part question and I have the first one done. Thank you in advance.
Okay so heres the question, part 1
"Find by customer, the total cost and the total discounted cost for each product on the order ?".
It also asks to use inner joins to find the customer and order it a specific way. Below is the answer.
SELECT
C.companyname, O.orderid, O.orderdate, P.productname,
OD.orderid, OD.unitprice, OD.qty, OD.discount,
(OD.unitprice * OD.qty - (OD.qty * OD.discount)) AS TotalCost,
(OD.qty * OD.discount) AS TotalDiscountedCost
FROM
Sales.Customers AS C
INNER JOIN
Sales.Orders AS O ON C.custid = O.custid
INNER JOIN
Sales.OrderDetails OD ON O.orderid = OD.orderid
INNER JOIN
Production.Products as P ON OD.productid = P.productid
ORDER BY
C.companyname, O.orderdate;
Now the second question is to
follow up and resume the first one by "customer and the order date year, the total cost and the total discounted cost on the order ?". It also asks for this, "Project following columns in the select clause as.
GroupByColumns.companyname
GroupByColumns.OrderdateYear
AggregationColumns.CountNumberOfIndividualOrders
AggregationColumns.CountNumberOfProductsOrders
AggregationColumns.TotalCost
AggregationColumns.TotalDiscountedCost
Finally to order by company name and orderdateYear( which are groups). Where im stuck is how to count the specific orders of qty that equal 1 as an aggregate function in the SELECT clause. I know it has to use the aggregate function COUNT because of the GROUP BY, just don't know how to. This is what I have.
SELECT
C.companyname, YEAR(O.orderdate) AS orderyear,OD.qty,
-- Where in the count function or if theres another way do I count all the
--single orders
--COUNT(OD.qty) AS indiviualorders,
(OD.unitprice * OD.qty - (OD.qty * OD.discount)) AS TotalCost,
(OD.qty * OD.discount) AS TotalDiscountedCost
FROM
Sales.Customers AS C
INNER JOIN
Sales.Orders AS O ON C.custid = O.custid
INNER JOIN
Sales.OrderDetails OD ON O.orderid = OD.orderid
INNER JOIN
Production.Products as P ON OD.productid = P.productid
GROUP BY
C.companyname, YEAR(O.orderdate)
ORDER BY
C.companyname, O.orderdate;
You case use a case statement inside a sum
SUM(CASE WHEN <xyz> THEN 1 ELSE 0 END)
But for the count of unique orders, use SELECT(DISTINCT ) on a key that is unique in the order table
SELECT COUNT(DISTINCT O.OrderID) As DistinctOrders FROM Table

Getting max value before given date

I am pretty new to using MS SQL 2012 and I am trying to create a query that will:
Report the order id, the order date and the employee id that processed the order
report the maximum shipping cost among the orders processed by the same employee prior to that order
This is the code that I've come up with, but it returns the freight of the particular order date. Whereas I am trying to get the maximum freight from all the orders before the particular order.
select o.employeeid, o.orderid, o.orderdate, t2.maxfreight
from orders o
inner join
(
select employeeid, orderdate, max(freight) as maxfreight
from orders
group by EmployeeID, OrderDate
) t2
on o.EmployeeID = t2.EmployeeID
inner join
(
select employeeid, max(orderdate) as mostRecentOrderDate
from Orders
group by EmployeeID
) t3
on t2.EmployeeID = t3.EmployeeID
where o.freight = t2.maxfreight and t2.orderdate < t3.mostRecentOrderDate
Step one is to read the order:
select o.employeeid, o.orderid, o.orderdate
from orders o
where o.orderid = #ParticularOrder;
That gives you everything you need to go out and get the previous orders from the same employee and join each one to the row you get from above.
select o.employeeid, o.orderid, o.orderdate, o2.freight
from orders o
join orders o2
on o2.employeeid = o.employeeid
and o2.orderdate < o.orderdate
where o.orderid = #ParticularOrder;
Now you have a whole bunch of rows with the first three values the same and the fourth is the freight cost of each previous order. So just group by the first three fields and select the maximum of the previous orders.
select o.employeeid, o.orderid, o.orderdate, max( o2.freight ) as maxfreight
from orders o
join orders o2
on o2.employeeid = o.employeeid
and o2.orderdate < o.orderdate
where o.orderid = #ParticularOrder
group by o.employeeid, o.orderid, o.orderdate;
Done. Build your query in stages and many times it will turn out to be much simpler than you at first thought.
It is unclear why you are using t3. From the question it doesn't sound like the employee's most recent order date is relevant at all, unless I am misunderstanding (which is absolutely possible).
I believe the issue lies in t2. You are grouping by orderdate, which will return the max freight for that date and employeeid, as you describe. You need to calculate a maximum total from all orders that occurred before the date that the order occurred on, for that employee, for every row you are returning.
It probably makes more sense to use a subquery for this.
SELECT o.employeeid, o.orderid, o.orderdate, m.maxfreight
FROM
orders o LEFT OUTER JOIN
(SELECT max(freight) as maxfreight
FROM orders AS f
WHERE f.orderdate <= o.orderdate AND f.employeeid = o.employeeid
) AS m
Hoping this is syntactically correct as I'm not in front of SSMS right now. I also included a left outer join as your previous query with an inner join would have excluded any rows where an employee had no previous orders (i.e. first order ever).
You can do what you want with a correlated subquery or apply. Here is one way:
select o.employeeid, o.orderid, o.orderdate, t2.maxfreight
from orders o outer apply
(select max(freight) as maxfreight
from orders o2
where o2.employeeid = o.employeid and
o2.orderdate < o.orderdate
) t2;
In SQL Server 2012+, you can also do this with a cumulative maximum:
select o.employeeid, o.orderid, o.orderdate,
max(freight) over (partition by employeeid
order by o.orderdate rows between unbounded preceding and 1 preceding
) as maxfreight
from orders o;

SQL Query to find the maximum of a set of averages

This is a query based on the Northwind Database in MS SQL Server 2005.
First I have to get the average of the UnitPrice from OrderDetails table, and group it by ProductID for that particular column alone and alias it as AveragePrice.
Then I need to find the maximum(AveragePrice) which is nothing but the max of previous column, how can I do it??? This is a kind of very tricky for me its taking me ages to think on it.
select
O.CustomerID,
E.EmployeeID,
E.FirstName+space(1)+E.LastName FullName,
OD.OrderID,
OD.ProductID,
(select avg(DO.UnitPrice) from OrderDetails
DO where OD.ProductID = DO.ProductID
group by DO.ProductID) AveragePrice ,
from OrderDetails OD
join Orders O
on OD.OrderID = O.OrderID
join Customers C
on C.CustomerID = O.CustomerID
join Employees E
on E.EmployeeID = O.EmployeeID
This is not a Homework question, am learning SQL, but am really stuck at this point, please help me.
It's 2 steps: "the ungrouped maximum of the grouped averages"
You can expand this as needed which shows how to apply an aggregate on top of an aggregate
SELECT
MAX(AveragePrice) AS MaxAveragePrice
FROM
(
select
avg(UnitPrice) AS AveragePrice, ProductID
from
OrderDetails
group by
ProductID
) foo
Or with CTE
;WITH AvgStuff AS
(
select
avg(UnitPrice) AS AveragePrice
from
OrderDetails
group by
ProductID
)
SELECT
MAX(AveragePrice) AS MaxAveragePrice
FROM
AvgStuff