I have three linked tables in SQL Server (Customers, Policies and Claims), and need to get a record for each Customer showing their most recent Policy, and within that Policy, their most recent Claim. The highest PolicyID for the Customer is their most recent Policy, and the highest ClaimID is the most recent Claim for the Policy.
I have the following query to show all Policies/Claims, but how do I restrict them to the most recent/highest IDs?
SELECT C.CustomerID, C.FirstName, C.LastName, P.PolicyID, P.PolicyDate, P.PolicyType, CL.ClaimID, CL.ClaimDate, CL.ClaimDescription
FROM Customers C INNER JOIN Policies P ON C.CustomerID = P.CustomerID
INNER JOIN Claims CL ON P.PolicyID = CL.PolicyID
try this,
;WITH CTE AS
(
SELECT C.CustomerID, C.FirstName, C.LastName, P.PolicyID, P.PolicyDate, P.PolicyType, CL.ClaimID, CL.ClaimDate, CL.ClaimDescription
,ROW_NUMBER() OVER(PARTITION BY C.CustomerID ORDER BY P.PolicyID DESC) PolicyOrder
,ROW_NUMBER() OVER(PARTITION BY C.CustomerID, P.PolicyID ORDER BY CL.ClaimID DESC) ClaimOrder
FROM Customers C INNER JOIN Policies P ON C.CustomerID = P.CustomerID
INNER JOIN Claims CL ON P.PolicyID = CL.PolicyID
)
SELECT
*
FROM CTE c
WHERE c.PolicyOrder = 1
AND c.ClaimOrder = 1
Related
I have one customer table and one address table.For each customer there should be multiple address in address Table
I need A stored procedure to select a customer details and his address on top from address table
parameter to select customer is companyID
SELECT top 1 s.Addr1 as ShipAddress_Addr1,s.Addr2 as ShipAddress_Addr2,s.Addr3 as ShipAddress_Addr3,
s.Addr4 as ShipAddress_Addr4,s.Addr5 as ShipAddress_Addr5,
s.City as ShipAddress_City,s.[state] as ShipAddress_State,s.PostalCode as ShipAddress_PostalCode,
s.Country as ShipAddress_Country,s.Note as ShipAddress_Note ,c.CustomerID,c.[TimeCreated], c.[FullName],c.FirstName,c.LastName,c.Phone, c.Email,
c.BillAddress_Addr1, c.[BillAddress_Addr2],c. [BillAddress_Addr3],c. [BillAddress_Addr4],c.[BillAddress_Addr5],
c.BillAddress_City,c.BillAddress_State,c.BillAddress_PostalCode,c.BillAddress_Country,c.BillAddress_Note
FROM Customer c left join [dbo].[CustomerShipToAddress] s on s.customerListID=c.CustomerID
WHERE c.IsActive = 1 and c.CompanyID = #CompanyID
You can outer apply the latest address for each customer like this:
select c.customerid, c.name, c.accno, c.txnid, ta.add1, ta.add2
from customertable c
outer apply (select top 1 a.add1, a.add2 from addresstable a where a.customerid = c.customerid order by a.addressid desc) ta
The sub-query in the outer apply with always return 0 or 1 rows for each customer, so it will not cause duplication of rows when you join it with customertable.
SELECT TOP 1, c.customerid, c.name, a.add1 FROM customertable c, addresstable a WHERE c.customerid == a.customerid
this will return the first row basically. this is what you are asking for, but not what you mean i assume.
if you want to look this up for a specific customer use
SELECT TOP 1, c.customerid, c.name, a.add1 FROM customertable c, addresstable a WHERE c.customerid == a.customerid AND c.customerid == "yourcustomerid"
or even
SELECT c.customerid, c.name, DISTINCT a.add1 FROM customertable c, addresstable a WHERE c.customerid == a.customerid
I'm trying to rank a query by not just one count, but by two.
I want to rank customers by the order items per orders.
WITH CTE AS
(
SELECT
o.CustomerId,
COUNT(DISTINCT o.OrderId) AS OrderCount,
COUNT(oi.OrderItemId) AS OrderItemCount
FROM
OrderItem oi
INNER JOIN
Order o ON o.OrderId = oi.OrderId
WHERE
o.CategoryId = 52 -- website sales
GROUP BY
o.CustomerId
)
SELECT
cust.Code,
cust.DisplayTitle,
CTE.OrderCount,
CTE.OrderItemCount,
--AVG(CTE.OrderItemCount/CTE.OrderCount) AS SumProduct ????
FROM
CTE
INNER JOIN
Customer cust ON cust.CustomerId = CTE.CustomerId
GROUP BY
cust.Code,
cust.DisplayTitle,
CTE.OrderCount,
CTE.OrderItemCount
ORDER BY
SumProduct DESC
I'm basically trying to implement the T-SQL equivalent of SUMPRODUCT() in Excel.
SELECT
o.CustomerId,
COUNT(DISTINCT o.OrderId) AS OrderCount,
COUNT(oi.OrderItemId) AS OrderItemCount,
COUNT(oi.OrderItemId) / COUNT(DISTINCT o.OrderId) avg
FROM OrderItem oi
INNER JOIN Order o ON o.OrderId = oi.OrderId
WHERE o.CategoryId = 52 -- website sales
GROUP BY o.CustomerId
order by COUNT(oi.OrderItemId) / COUNT(DISTINCT o.OrderId) desc
Just add in the join to customer
I am learning window functions in sql server. I am using AdventrueWorks2012 database for practice. I want to calculate total number of sales and purchases for each item in the store.
The classic solution can be like
SELECT ProductID,
Quantity,
(SELECT Count(*)
FROM AdventureWorks.Purchasing.PurchaseOrderDetail
WHERE PurchaseOrderDetail.ProductID = p.ProductID) TotalPurchases,
(SELECT Count(*)
FROM AdventureWorks.Sales.SalesOrderDetail
WHERE SalesOrderDetail.ProductID = p.ProductID) TotalSales
FROM (SELECT DISTINCT ProductID,
Quantity
FROM AdventureWorks.Production.ProductInventory) p
Trying to convert to window functions gives me wrong results:
SELECT DISTINCT d.ProductID,
Quantity,
Count(d.ProductID)
OVER(
PARTITION BY d.ProductID) TotalPurchases,
Count(d2.ProductID)
OVER(
PARTITION BY d2.ProductID) TotalSales
FROM (SELECT DISTINCT ProductID,
Quantity
FROM AdventureWorks.Production.ProductInventory) p
INNER JOIN AdventureWorks.Purchasing.PurchaseOrderDetail d
ON p.ProductID = d.ProductID
INNER JOIN AdventureWorks.Sales.SalesOrderDetail d2
ON p.ProductID = d2.ProductID
ORDER BY d.ProductID
Why this is wrong? How can I correct it?
You should change INNER JOIN to LEFT JOIN
Because when you inner join, result will miss productid which from ProductInventory table does not have PurchaseOrderDetail or SalesOrderDetail.
I was trying to write a query for the SQL Server sample DB Northwind. The question was: "Show the most recent five orders that were purchased by a customer who has spent more than $25,000 with Northwind."
In my query the Alias name - "Amount" is not being recognized. My query is as follows:
select top(5) a.customerid, sum(b.unitprice*b.quantity) as "Amount", max(c.orderdate) as Orderdate
from customers a join orders c
on a.customerid = c.customerid
join [order details] b
on c.orderid = b.orderid
group by a.customerid
--having Amount > 25000 --throws error
having sum(b.unitprice*b.quantity) > 25000 --works, but I don't think that this is a good solution
order by Orderdate desc
Pls let me know what I am doing wrong here, as I am a newbie in writing T Sql. Also can this query and my logic be treated as production level query?
TIA,
You must use the aggregate in the query you have. This all has to do with the order in which a SELECT statement is executed. The syntax of the SELECT statement is as follows:
SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
The order in which a SELECT statement is executed is as follows. Since the SELECT clause isn't executed until after the HAVING clause, you can't use the alias like you can in the ORDER BY clause.
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
Reference Article: http://www.bennadel.com/blog/70-sql-query-order-of-operations.htm
This is a known limitation in SQL Server, at least, but no idea if it's a bug, intentional or even part of the standard. But the thing is, neither the WHERE or HAVING clauses accept an alias as part of their conditions, you must use only columns from the original source tables, which means that for filtering by calculated expressions, you must copy-paste the very same thing in both the SELECT and WHERE parts.
A workaround for avoiding this duplication can be to use a subquery or cte and apply the filter on the outer query, when the alias is just an "input" table:
WITH TopOrders AS (
select a.customerid, sum(b.unitprice*b.quantity) as "Amount", max(c.orderdate) as Orderdate
from customers a join orders c
on a.customerid = c.customerid
join [order details] b
on c.orderid = b.orderid
group by a.customerid
--no filter here
order by Orderdate desc
)
SELECT TOP(5) * FROM TopOrders WHERE Amount > 25000 ;
Interesting enough, the ORDER BY clause does accepts aliases directly.
You must use Where b.unitprice*b.quantity > 25000 instead of having Amount > 25000.
Having used for aggregate conditions. Your business determine your query condition. If you need to calculate sum of prices that have above value than 25000, must be use Where b.unitprice*b.quantity > 25000 and if you need to show customer that have total price above than 25000 must be use having Amount > 25000 in your query.
select top(5) a.customerid, sum(b.unitprice*b.quantity) as Amount, max(c.orderdate) as Orderdate
from customers a
JOIN orders c ON a.customerid = c.customerid
join [order details] b ON c.orderid = b.orderid
group by a.customerid
having sum(b.unitprice*b.quantity) > 25000 --works, but I don't think that this is a good solution
Order by Amount
I don't have that schema at hand, so table' and column' names might go a little astray, but the principle is the same:
select top (5) ord2.*
from (
select top (1) ord.CustomerId
from dbo.Orders ord
inner join dbo.[Order Details] od on od.OrderId = ord.OrderId
group by ord.CustomerId
having sum(od.unitPrice * od.Quantity) > $25000
) sq
inner join dbo.Orders ord2 on ord2.CustomerId = sq.CustomerId
order by ord2.OrderDate desc;
The Having Clause will works with aggregate function like SUM,MAX,AVG..
You may try like this
SELECT TOP 5 customerid,SUM(Amount)Amount , MAX(Orderdate) Orderdate
FROM
(
SELECT A.customerid, (B.unitprice * B.quantity) As "Amount", C.orderdate As Orderdate
FROM customers A JOIN orders C ON A.customerid = C.customerid
JOIN [order details] B ON C.orderid = B.orderid
) Tmp
GROUP BY customerid
HAVING SUM(Amount) > 25000
ORDER BY Orderdate DESC
The question is little ambiguos.
Show the most recent five orders that were purchased by a customer who
has spent more than $25,000 with Northwind.
Is it asking to show the 5 recent orders by all the customers who have spent more than $25,000 in all of their transactions (which can be more than 5).
The following query shows all the customers who spent $25000 in all of their transactions (not just the recent 5).
In one of the Subquery BigSpenders it gets all the Customers who spent more than $25000.
Another Subquery calculates the total amount for each order.
Then it gets rank of all the orders by OrderDate and OrderID.
Then it filters it by Top 5 orders for each customer.
--
SELECT *
FROM (SELECT C.customerid,
C.orderdate,
C.orderid,
B3.amount,
Row_number()
OVER(
partition BY C.customerid
ORDER BY C.orderdate DESC, C.orderid DESC) Rank
FROM orders C
JOIN
--Get Amount Spend Per Order
(SELECT b2.orderid,
Sum(b2.unitprice * b2.quantity) AS Amount
FROM [order details] b2
GROUP BY b2.orderid) B3
ON C.orderid = B3.orderid
JOIN
--Get Customers who spent more than 25000
(SELECT c.customerid
FROM orders c
JOIN [order details] b
ON c.orderid = b.orderid
GROUP BY c.customerid
HAVING Sum(b.unitprice * b.quantity) > 25000) BigSpenders
ON C.customerid = BigSpenders.customerid) X
WHERE X.rank <= 5
Good day,
In a WHILE statement I am running, one of the variable assignments I'm attempting is to use a sub query in conjunction with row_number() to pull out each specific ID from a column and sum a monetary value from another table, per each ID. I am working in MS SQL 2008.
Here is the query I have so far:
SET #value =(SELECT PaymentAmount FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY C.CategoryID ASC) AS RowNum,
SUM(O.PaymentAmount)
FROM Orders O
INNER JOIN OrderDetails OD ON O.OrderID = OD.OrderID
INNER JOIN Products_Joined PJ ON OD.ProductCode = PJ.ProductCode
INNER JOIN Categories_Products_Link CPL ON PJ.ProductID = CPL.ProductID
INNER JOIN Categories C ON CPL.CategoryID = C.CategoryID
GROUP BY C.CategoryID
) AS Num
WHERE RowNum = #counter)
The error I'm running into is in regards to no column was specified for column 2 of 'Num'.
Thoughts? Ideas? Thanks for your time!