Getting Latest/Top orderID for each customer in SQL Server - sql

I have a database where it records all the orders of customers. What I'm trying to do is not to get all the orders of each customer, but the latest order the customer made with us. I have already do this by using Sub-Select statement, but because of how many data there is, it is taking alot of time to retrieve. So I was wondering is there another way around this that can speed it up?
Here's the code of using Sub-Select statement I've written:
SELECT Customer.CustomerId,
Customer.Firstname + ' ' + Customer.Surname AS [Customer Name],
(SELECT TOP(1) Orders.OrderId
FROM Orders
WHERE Orders.CustomerId = Customer.CustomerId
ORDER BY Orders.OrderId DESC),
(SELECT TOP(1) Orders.Item
FROM Orders
WHERE Orders.CustomerId = Customer.CustomerId
ORDER BY Orders.OrderId DESC)
FROM Customer
Any help or info on how to improve this will be greatly appreciated.
Thanks

If there are indexes created ,rebuilt/refresh the indexes which will help in increasing the performance of the query.
Try creating non clustered indexes which will speed up the execution of the query.

might be this is helpful for you
WITH cte AS (
SELECT c.CustomerName,
c.OrderID,
ROW_NUMBER() OVER(PARTITION BY c.CustomerName
ORDER BY c.CustomerName DESC) AS rk
FROM Customers c
join Orders j c.OrderID = j.OrderId
)
SELECT a.*
FROM cte a
WHERE a.rk = 1

Sometimes using row_number gives better results, so you could try something like this:
select * from (
SELECT
C.CustomerId,
C.Firstname + ' ' + C.Surname AS [Customer Name],
O.OrderId,
O.Item,
row_number() over (partition by O.CustomerId order by O.OrderId desc) as RN
FROM
Customer C
join Orders O on O.CustomerId = O.CustomerId
) X
where RN = 1
If there's a lot of orders and customers this can be slow too since there's no search criteria. You should also check indexing, especially Orders.CustomerId.
Didn't try this, so hopefully there's no syntax errors :)

Try this :
SELECT T1.CustomerID,T1.OrderID,T2.OrderItem
FROM
(SELECT C.CustomerID,MAX(O.OrderID) as OrderID
FROM Customer C JOIN
Orders O ON C.CustomerID=O.CustomerID
GROUP BY C.CustomerID) T1
JOIN
(SELECT OrderID,Item
FROM Orders) T2 ON T1.OrderID=T2.OrderID
Sample result in SQL Fiddle.

Related

Find customer who bought least on W3schools SQL

I'm new to SQL Server and I'm trying to do some exercises. I want to find customers who bought least on W3schools database. My solution for this case is:
Join Customers with OrderDetails via CustomerID
Select CustomerNames that have least OrderID appeared after using JOIN.
Here is my query:
SELECT COUNT(OrderID), CustomerID
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(CustomerID) ASC
HAVING COUNT(OrderID) = '1'
When I ran this query, message says "Syntax error near "Having". What happened with my query?
Please help me to figure out.
My solution for this case is:
Join Customers with OrderDetails via CustomerID
Select CustomerNames that have least OrderID appeared after using JOIN.
As #thorsten-kettner lamented:
You say in your explanation that you join and then show the customer
name. Your query does neither of the two things...
Furthermore, your question has severe grammatical errors making it hard to decipher.
I want to find customers who bought least on W3schools database.
Nonetheless,
The Try-SQL Editor at w3schools.com
To get the list of customers who have at least 1 order:
SELECT C.CustomerName FROM [Customers] AS C
JOIN [Orders] AS O
ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
ORDER BY C.CustomerName
To get the list of customers who have exactly 1 order:
SELECT C.CustomerName FROM [Customers] AS C
JOIN [Orders] AS O
ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
HAVING COUNT(O.OrderID) = 1
ORDER BY C.CustomerName
To get the customer who made the least number of orders:
Including the ones who made no order. Use JOIN instead of LEFT JOIN if you only want to consider the ones who made at least one order.
You can remove LIMIT 1 to get the whole list sorted by the number of orders placed.
SELECT C.CustomerName, COUNT(O.OrderID) FROM [Customers] AS C
LEFT JOIN [Orders] AS O
ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
ORDER BY COUNT(O.OrderID), C.CustomerName
LIMIT 1;
Addendum
As commented by #sticky-bit ,
The ORDER BY clause has to come after the HAVING clause.
You want a TOP 1 WITH TIES query, something like this:
SELECT TOP 1 WITH TIES CustomerID
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(OrderID);
In case you are using MySQL, try the following version:
SELECT CustomerID
FROM Orders
GROUP BY CustomerID
HAVING COUNT(OrderID) = (
SELECT COUNT(OrderID)
FROM ORDERS
GROUP BY CustomerID
ORDER BY COUNT(OrderID)
LIMIT 1
);

Access Query from multiple tables

I currently have an Access Database with a few tables, among them Order, OrderDetails and Client.
Order (OrderID, TimeStamp, FKEmployeeID, FKClientID, OrderStatus, Comments)
OrderDetails (OrderDetailsID, FKOrderID, FKProductID, Quantity, Cost, Total Cost)
Client (ClientID, Name)
I'm trying to build a query where I can get the total orders that a client has made and the total Items.
Example:
Customer, Total Orders, Total Items
John, 5, 15
Alex, 2, 30
Ana, 1, 3
Whenever I try to make a query Total Orders and Total Items give me the same number.
Any help would be greatly appreciated!
This is supported even by ms access:
SELECT c.Name,
(select count(*)
from Orders o
where o. FKClientID = C.ClientID) as [Total Orders],
(select sum(Quantity) as Items
from OrderDetails od
inner join Order o on o.OrderID = od.FKOrderID
where o.FKClientId = C.ClientID) as [Total Items]
from Client c;
Unfortunately, MS Access doesn't support COUNT(DISTINCT). You can do this with two aggregations:
SELECT c.[Name], COUNT(*) As NumOrders, SUM(o.NumItems) As NumItems
FROM Client as c INNER JOIN
(SELECT o.OrderID, o.FKClientID, COUNT(*) As NumItems
FROM [Order] as o INNER JOIN
OrderDetails as od
ON od.FKOrderID = o.OrderID
GROUP BY o.OrderID, o.FKClientID
) as o
ON o.FKClientID = c.ClientId
GROUP BY c.ClientId, c.Name;
What about this solution (clients without orders are left out hereby):
SELECT Client.[Name],
Count(myTotalItems.OrderID) As TotalOrders,
Sum(myTotalItems.TotalItems) As TotalItems
FROM Client,
(SELECT First([Order].OrderID) As OrderID,
First([Order].FKClientID) As
ClientID,
Count(OrderDetails.OrderDetailsID) As TotalItems
FROM [Order], OrderDetails
WHERE OrderDetails.FKOrderID like [Order].OrderID
GROUP BY [Order].OrderID) As myTotalItems
WHERE myTotalItems.ClientID like Client.ClientID
GROUP BY Client.[Name];
It would be easier for you if you divide the task into multiple queries. I am giving the sample using Northwind database, you can test and see on it. Note that the structures and fieldnames are very similar to yours.
First create one that gets ClientId, OrderId, OrderDate and Sum of Quantity.
SELECT c.CustomerId, o.OrderId, o.OrderDate, sum(od.Quantity) AS Qty
FROM (Customers AS c INNER JOIN Orders AS o ON c.CustomerId = o.CustomerId)
INNER JOIN [Order Details] AS od ON o.OrderId = od.OrderID
GROUP BY c.CustomerId, o.OrderId, o.OrderDate;
Save this as "OrderOfClients" (it would be saved in Queries). Next create a query that uses this one and asks for date range:
SELECT c.CustomerId, c.CompanyName,
Count(*) AS [Total Orders],
Sum(Qty) AS [Total Items]
FROM Customers AS c
INNER JOIN OrdersOfClients AS co ON c.CustomerId = co.CustomerId
WHERE co.OrderDate Between [#startDate] And [#endDate]
GROUP BY c.CustomerId, c.CompanyName;
You can save this one as "OrdersOfClientsSummary" and call for your report.
PS: In my personal opinion, if you use a database other than access you would be doing yourself a big favor.

SQL TOP 1 Syntax for a nested query

New to SQL Server and I am trying to use top 1 to get the company with the most order in my DB within my code that is already working but I don't know how to use it properly. Only missing syntax I think.
Query #1 is working fine:
SELECT
c.CompanyName, COUNT(DISTINCT OrderID) as Nombre_Commande
FROM
Orders O
INNER JOIN
Customers C ON O.CustomerID = c.CustomerID
GROUP BY
c.CompanyName
What I am trying to do
SELECT TOP (1) *
FROM
(SELECT
c.CompanyName, COUNT(DISTINCT OrderID) AS Nombre_Commande
FROM
Orders O
INNER JOIN
Customers C ON O.CustomerID = c.CustomerID
GROUP BY
c.CompanyName)
You need to give the derived table an alias, and also, specifying top without an order by clause is pretty pointless as rows are returned as a set without any order unless the order is explicitly specified with an order by clause:
SELECT TOP (1) *
FROM (
SELECT c.CompanyName, COUNT(DISTINCT OrderID) as Nombre_Commande
FROM Orders O
INNER JOIN Customers C ON O.CustomerID=c.CustomerID
GROUP by c.CompanyName
) AS YourTable
ORDER BY something_meaningful_maybe_nombre_commande?
How about this?
SELECT TOP 1 c.CompanyName, COUNT(DISTINCT OrderID) as Nombre_Commande
FROM Orders O INNER JOIN
Customers C
ON O.CustomerID = c.CustomerID
GROUP by c.CompanyName
ORDER BY Nombre_Commande DESC;
This assumes that Nombre_Commande is what you want to order by.
By the way, I would be surprised if COUNT(DISTINCT) were really needed for this query. COUNT(*) or COUNT(OrderId) should be sufficient.

Query to pull second order date for a customer(SQL 2014)

I have a schema with customers, orders and order dates.
A customer can have orders in multiple dates. I need a calculated member to bring the first order date and the second order date with other associated metrics.
I was able to get the first order date and associated data using min(order date) as a first order but having issues querying for the second order date. Any suggestion would help! Thanks
my query
---I have all the information in one table so my query looks like
Select customerid, order id, min(orderdate) as firstorderdate,...
From customer Where first ordedate between 01/01/2015’ and GETDATE()
(since I only want those customers who made their first purchase this year)
Query their second purchase
Select customerid, orderid, orderdate from ( select customerid,
orderid, orderdate, rwo_number() over (partition by customerid,
orderid order by orderdate) rn from customer
Where rn<=2
Without seeing your current query, it's difficult to understand. I assume your current query is like this:
select c.customerid, o.orderid, min(od.orderdate)
from customers c
join orders o on c.customerid = o.customerid
join orderdates od on o.orderid = od.orderid
group by c.customerid, o.orderid
Another way of doing the same query is to use row_number. Doing it this way, you're not restricted to just the first in the group:
select customerid, orderid, orderdate
from (
select c.customerid, o.orderid, od.orderdate,
row_number() over (partition by c.customerid, o.orderid
order by od.orderdate) rn
from customers c
join orders o on c.customerid = o.customerid
join orderdates od on o.orderid = od.orderid
) t
where rn <= 2

SQL INNER JOIN Without Repeats

Getting the next table:
Column1 - OrderID - Earliest orders of customers from Column2
Column2 - CustomerID - Customers from orders in Column1
Column3 - OrderID - All *Other* orders of customers from Column2
which do not appear in Column1
This is my query and I'm looking for a way to apply the rules mentioned above:
SELECT O1.orderid, C1.customerid, O2.Orderid
FROM orders AS O1
INNER JOIN customers AS C1 ON O1.customerid = C1.customerid
RIGHT JOIN orders AS O2 ON C1.customerid = O2.customerid
WHERE O1.orderdate >= '2014-01-01'
AND O1.orderdate <= '2014-03-31'
ORDER BY O1.orderid
Thanks in advance
Not entirely sure why you want to get a result out like this as the earliest order will repeat for each order for the given customer.
SELECT earliestOrders.orderid, C1.customerid, O1.Orderid
FROM orders AS O1
INNER JOIN customers AS C1 ON O1.customerid = C1.customerid
INNER JOIN (
select o.customerid, min(o.OrderId) as OrderId
from orders o
Group by o.customerid
) earliestOrders
ON earliestOrders.CustomerId = C1.CustomerId
AND earliestOrders.orderid <> O1.Orderid
To find the first order per customer, look for first order dates per customer and then pick the one or one of the orders made by the customer then. (If orderdate really is just a date one customer can have placed more than one order that day, so we pick one of them. With MIN(orderid) we are likely to get the first one of that bunch :-)
Outer join the other orders and you are done.
If your dbms supports IN clauses on tuples, you get a quite readable statement:
select first_order.orderid, first_order.customerid, later_order.orderid
from
(
select customerid, min(first_order.orderid) as first_orderid
from orders
where (customerid, orderdate) in
(
select customerid, min(orderdate)
from orders
group by cutomerid
)
) first_order
left join orders later_order
on later_order.customerid = first_order.customerid
and later_order.orderid <> first_order.orderid
;
If your dbms doesn't support IN clauses on tuples, the statement looks a bit more clumsy:
select first_order.orderid, first_order.customerid, later_order.orderid
from
(
select first_orders.customerid, min(first_orders.orderid) as orderid
from orders first_orders
inner join
(
select customerid, min(orderdate)
from orders
group by cutomerid
) first_order_dates
on first_order_dates.customerid = first_orders.customerid
and first_order_dates.orderdate = first_orders.orderdate
group by first_orders.customerid
) first_order
left join orders later_order
on later_order.customerid = first_order.customerid
and later_order.orderid <> first_order.orderid
;