SQL Server 2012 not getting values from subqueries - sql

I am pretty new to SQL Server 2012 and I am doing an exercise where I am trying to obtain
1)The EmployeeID, LastName, and FirstName for each employee
2)The OrderID and the total price of the most expensive order
3)The ShipName
I have gotten most of the way there, getting all the info for each employee and the total price of their most expensive order.
Here is the code I have gotten done so far:
select e.EmployeeID, e.FirstName, e.LastName, max(od.totPrice) as mostExpTotOrder
from Employees e
inner join
Orders o
on e.EmployeeID = o.EmployeeID
inner join
(
select OrderID, sum(unitprice) as totPrice
from [Order Details]
where discount = 0
group by OrderID
) od
on o.OrderID = od.OrderID
group by e.EmployeeID, e.FirstName, e.LastName
When I try to enter in o.OrderID and o.ShipName to the outer query, the query grabs every OrderID, whereas I am just trying to get the OrderID of the most expensive order each employee has processed.
select e.EmployeeID, e.FirstName, e.LastName, max(od.totPrice) as mostExpTotOrder, o.OrderID, o.ShipName
from Employees e
inner join
Orders o
on e.EmployeeID = o.EmployeeID
inner join
(
select OrderID, sum(unitprice) as totPrice
from [Order Details]
where discount = 0
group by OrderID
) od
on o.OrderID = od.OrderID
group by e.EmployeeID, e.FirstName, e.LastName, o.OrderID, o.ShipName
Am I missing something pretty basic?

When you add the order Id to the aggregation, Then you get what you ask for.
You are getting the max price per employee PER ORDER.
You didn't mention in any way in your query that you want the order for which the max price was associated to.
To achieve that, you'll need to join the Aggregated Query by the employee Id with the original query, for example by the employee Id and the Price (Assuming both will identify the row uniquely) and then select the order Id.
A small sample to demonstrate:
SELECT *
into #tmp
FROM
(
select 1 as OrderId , 1 as EmployeeId , 100 as Price
UNION
select 2 as OrderId , 1 as EmployeeId , 200 as Price
UNION
select 3 as OrderId , 2 as EmployeeId , 100 as Price
UNION
select 4 as OrderId , 2 as EmployeeId , 200 as Price
UNION
select 5 as OrderId , 2 as EmployeeId , 300 as Price
) a
SELECT a.* , b.OrderId
FROM (
SELECT EmployeeId , Max(Price) Price
FROM #tmp a
group by EmployeeId
) a
inner join #tmp b
on a.EmployeeId = b.EmployeeId
and a.Price = b.Price

Related

SQL double group by

I need to select employees' names from those who has sold products, for the biggest total sum of money in each of the years, in Northwind database. I've managed to create a valid query like this:
WITH TEMP_QUERY AS
(
SELECT
DATEPART(YEAR, OrderDate) AS 'Year'
,FirstName + ' ' + LastName AS 'Employee'
,SUM(UnitPrice * Quantity) AS 'Total year sale'
FROM Employees
INNER JOIN Orders
ON Employees.EmployeeID = Orders.EmployeeID
INNER JOIN [Order Details]
ON Orders.OrderID = [Order Details].OrderID
GROUP BY FirstName + ' ' + LastName, DATEPART(YEAR, OrderDate)
)
SELECT
DATEPART(YEAR, OrderDate) AS 'Year'
,FirstName + ' ' + LastName AS 'Employee'
,SUM(UnitPrice * Quantity) AS 'Total year sale'
FROM Employees
INNER JOIN Orders
ON Employees.EmployeeID = Orders.EmployeeID
INNER JOIN [Order Details]
ON Orders.OrderID = [Order Details].OrderID
GROUP BY
FirstName + ' ' + LastName
,DATEPART(YEAR, OrderDate)
HAVING SUM(UnitPrice * Quantity) IN
(
SELECT MAX(main.[Total year sale]) FROM TEMP_QUERY AS main
INNER JOIN TEMP_QUERY AS e ON e.Employee = main.Employee
GROUP BY main.Year
)
ORDER BY 1;
However I wonder if there's a simpler way of doing this with or without CTE (probably is)
Database scheme.
https://docs.yugabyte.com/images/sample-data/northwind/northwind-er-diagram.png
First, your main query is the same as those one used in CTE (except HAVING and ORDER BY clauses), so you can just write it as SELECT ... FROM temp_query.
Second, I suggest you not to use the combination of FirstName and LastName for aggregation in CTE, since in theory there can be multiple rows for different employees with same values. You have the EmployeeId you a free to use it instead.
Third, since now the main query does not have any aggregation, you do not need a HAVING clause, it can be replaced by WHERE clause.
Fourth, the filter condition (in HAVING clause of your query) does not need self joining of CTE for getting the maximum of Total year sale. Just select MAX("Total year sale") with GROUP BY year.
Fifth, since I have suggested to use EmployeeId to perform the aggregation in CTE, join the Employees table to get the corresponding FirstName and LastName values for an employee in results.
Finally the query would look like this
WITH employee_total_sales (
SELECT
e.employeeid,
DATEPART(YEAR, OrderDate) AS year,
SUM(UnitPrice * Quantity) AS total_sale
FROM Employees e
INNER JOIN Orders o ON e.EmployeeID = o.EmployeeID
INNER JOIN [Order Details] od ON o.OrderID = od.OrderID
GROUP BY e.employeeid, DATEPART(YEAR, OrderDate)
)
SELECT
year AS "Year",
FirstName + ' ' + LastName AS "Employee",
total_sale AS "Total year sale"
FROM employee_total_sales ets
JOIN employees e ON e.employeeid = ets.employeeid
WHERE total_sales IN (
SELECT
MAX(total_sale)
FROM employee_total_sales
GROUP BY year
)
ORDER BY year

How can i show the last order and the one before the last?

This is the question:
Write a query that shows for each customer the last order date he placed and the order date before the last
View: FirstName, LastName, CustomerID, SalesOrderID, Last Order Date, and one before.
That's what I need to get in the end:
This is my code:
WITH CTE
AS
(
SELECT S.SalesOrderID, C.CustomerID, C.PersonID, p.LastName, p.FirstName, S.OrderDate LastOrder,
lag(orderdate,1)OVER(PARTITION By C.personid ORDER BY orderdate ) PreviousOrder
FROM sales.SalesOrderHeader S JOIN Sales.Customer C
ON s.CustomerID =c.CustomerID
JOIN Person.Person p
ON P.BusinessEntityID=C.PersonID
)
SELECT SalesOrderID,CustomerID,LastName , FirstName ,LastOrder,PreviousOrder
FROM CTE E
WHERE LastOrder in (SELECT MAX(LastOrder)
FROM cte i
WHERE c.CustomerID=i.CustomerID
)

Find employee who made highest sales to the customer who made most purchases

I'm having trouble with this question in my Database homework And need to answer this question:
Which employee has the highest sales to the customer who has made the most purchases?
And these are my database tables
And these are my attempts to write this query
--select Customers.Firstname,Products.Name,Sales.Quantity from Customers
--inner join Sales
--on Customers.CustomerId=Sales.CustomerId
--inner join Products
--on Sales.productId=Products.ProductId
--where Products.Name like 'Mobile'
--Select Customers.CustomerId,max(COUNT(Customers.CustomerId)) As Customecount,Emploees.EmploeeId,max(COUNT(Emploees.EmploeeId))as EmploeeeCount from Emploees
--inner join Sales
--on Emploees.EmploeeId=Sales.EmploeeId
--inner join Customers
--on Customers.CustomerId=Sales.CustomerId
--group by Customers.CustomerId,Emploees.EmploeeId ,Count(Sales.productId)as productCount,Count(Emploees.EmploeeId)as emploeeCount,Count(Customers.CustomerId)as customerCount
select * from
(select Distinct Customers.CustomerId,Sales.productId,COUNT(Sales.productId)as CountProduct from Customers
inner join Sales
on Customers.CustomerId=Sales.CustomerId
inner join Emploees
on Emploees.EmploeeId=Sales.EmploeeId
group by Sales.productId,Emploees.EmploeeId,Customers.CustomerId,Sales.productId) as Result
--gr
But these don't work
Please, help me to write this Query.
Try to solve the problem step by step. Find the customer id with most orders by total:
SELECT TOP 1 sales.customerid
FROM sales
JOIN products ON sales.productid = products.productid
GROUP BY sales.customerid
ORDER BY SUM(sales.quantity * products.price) DESC
Next step is to find the employee with most sales by count to that customer (changing it to by total is trivial):
SELECT TOP 1 sales.salespersonid
FROM sales
WHERE sales.customerid = (
SELECT TOP 1 sales.customerid
FROM sales
JOIN products ON sales.productid = products.productid
GROUP BY sales.customerid
ORDER BY SUM(sales.quantity * products.price)
)
GROUP BY sales.salespersonid
ORDER BY COUNT(sales.salesid) DESC
Finally select the employee record:
SELECT *
FROM employee
WHERE employeeid = (
SELECT TOP 1 sales.salespersonid
FROM sales
WHERE sales.customerid = (
SELECT TOP 1 sales.customerid
FROM sales
JOIN products ON sales.productid = products.productid
GROUP BY sales.customerid
ORDER BY SUM(sales.quantity * products.price)
)
GROUP BY sales.salespersonid
ORDER BY COUNT(sales.salesid) DESC
)
Maybe something like this....
First get the customer with most purchases and then find all employees who have sold to that customer and return the top 1 employee with the most sales.
SELECT TOP (1)
e.EmploeeId
, SUM(s.quantity * p.Price) TotalSales
FROM Emploees e
inner join Sales s ON e.EmploeeId = s.EmploeeId
inner join Product p ON s.productId = s.productId
WHERE s.CustomerId = (
-- Get the customer with most purchases
SELECT TOP (1) x.CustomerId
FROM ( SELECT
c.CustomerId
, SUM(s.quantity * p.Price) TotalSales
FROM Customers c
inner join Sales s ON c.CustomerId = s.CustomerId
inner join Product p ON s.productId = o.productId
GROUP BY c.CustomerId
) x
ORDER BY TotalSales DESC
)
GROUP BY e.EmploeeId
ORDER BY TotalSales DESC
To find Most Sales and Purchases by count (Number of sales/Purchases) following query will do the trick:
SELECT TOP (1)
e.EmploeeId
, COUNT(*) TotalSales
FROM Emploees e
inner join Sales s ON e.EmploeeId = s.EmploeeId
WHERE s.CustomerId = (
SELECT TOP (1) x.CustomerId
FROM ( SELECT
c.CustomerId
, COUNT(*) TotalSales
FROM Customers c
inner join Sales s ON c.CustomerId = s.CustomerId
GROUP BY c.CustomerId
) x
ORDER BY TotalSales DESC
)
GROUP BY e.EmploeeId
ORDER BY TotalSales DESC
In one of the comments you said that "most sales" mean more sale quantity. This answer takes this criteria into consideration.
SELECT TOP (1) SalesPersonID,
(FirstName + ' ' + MiddleName + ' ' + LastName) AS EmployeeName
FROM Sales S
JOIN Employees E ON S.SalesPersonID = E.EmployeeID
WHERE CustomerID =
(
-- Sub-query that returnes CustomerID with most quantities bought
SELECT TOP (1) CustomerID
FROM Sales
GROUP BY CustomerID
ORDER BY SUM(Quantity) DESC
)
GROUP BY SalesPersonID,
(FirstName + ' ' + MiddleName + ' ' + LastName)
ORDER BY SUM(Quantity)

Northwind - List of top ten employees

I have another trouble with my SQL queries.
My task is to create a list of top 10 employees, with the most sales in 1997.
So far I have this, simple query that shows me list of employees and which order they've sold.
SELECT
Orders.EmployeeID,
Orders.OrderID
FROM
Employees
JOIN
Orders ON Orders.EmployeeID = Employees.EmployeeID
ORDER BY
Orders.EmployeeID;
Now I want to group up those numbers, I need to know how many sales each employee did in 1997. How to do that?
You can get the results that you need without JOIN and GROUP BY if you order by results of a subquery:
SELECT TOP 10 *
FROM Employees e
ORDER BY (
SELECT COUNT(*)
FROM Sales s
WHERE s.EmployeeId=e.EmployeeId
AND DATEPART(year, o.OrderDate)=1997
) DESC
This yields top ten employees by the number of sales transactions.
If you need anything from Sales, say, the count, you would need to go the GROUP BY route:
SELECT TOP 10 * FROM (
SELECT e.EmployeeId, COUNT(*) AS SalesCount
FROM Employees e
LEFT OUTER JOIN Orders o ON o.EmployeeId=e.EmployeeId
AND DATEPART(year, o.OrderDate)=1997
GROUP BY e.EmployeeId
) groups
ORDER BY SalesCount DESC
WITH CTE AS
(
SELECT EmployeeId,COUNT(*) as cn,
DENSE_RANK(ORDER BY COUNT(*) DESC) AS rn
FROM orders
WHERE DATEPART(year,OrderDate)=1997
GROUP BY EmployeeId
)
SELECT e.*,COALESCE(o.cn,0) AS CountOrders
FROM Employees e
LEFT JOIN CTE o
ON e.EmployeeId=o.EmployeeId
WHERE o.rn<=10
It can reduce to this
SELECT top(10) EmployeeID, count(*) as cnt
FROM Orders
group by EmployeeID
ORDER BY count(*) desc;

Need to order output based on date - Sub query

I have a simple subquery where I have two tables. First table has the customer id, first name and last name. Second table has the customer id and order date. I want to generate a query that shows the first name, last name and order date.
I have tried the below code and i dont know how the order the output based on date
Select
Customerid,
FirstName,
LastName
From
Customer
Where
CustomerID IN (select
CustomerID
from
orders
where
orderdate is not null);
The output I show is only the customer id, first name and last name. How do I include the order date in my output.
what did u select = what will display for you, include date in your select statement
Select A.Customerid, A.firstname, A.lastname, B.orderdate
From tableA A
Inner join Tableb B on A.customerid = B.customerid
For your modified question(s), try query below
Select A.firstname, A.lastname, B.orderdate
From tableA A
Inner join Tableb B on A.customerid = B.customerid
Order By B.orederdate
;with CustomerProductOrderOrdinal( OrderId, Ordinal )
as
(
select
o.OrderId
, row_number() over ( partition by o.CustomerId, o.ProductId order by o.OrderDate ) Ordinal
from
Orders o
where
o.OrderDate is not null
-- filter for product here if so desired
-- and o.ProductId = <whatever>
)
,FirstCustomerProductOrder( OrderId )
as
(
select
OrderId
from
CustomerProductOrderOrdinal
where
Ordinal = 1
)
select
c.CustomerId
, c.FirstName
, c.LastName
--, p.ProductId
, o.OrderDate
From
Customer c
inner join Orders o
on c.CustomerId = o.CustomerId
inner join FirstCustomerProductOrder fcpo
on o.OrderId = fcpo.OrderId
-- join with product if you want product info
--inner join Product p
-- on o.ProductId = p.ProductId