sql server join and select top 1 - sql-server

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

Related

Select columns from several tables with count

I have 3 tables in SQL Server:
Sales (customerId)
Customer (customerId, personId)
Person (personId, firstName, lastName)
and I need to return the top 10 customers.
I used this query:
SELECT TOP 10
CustomerID, COUNT(CustomerID)
FROM
Sales
GROUP BY
(CustomerID)
ORDER BY
COUNT(CustomerID) DESC
The query currently returns only the customerId and count, but I also need to return the firstName and lastName of these customers from the Person table.
I know I need to reach the firstName and lastName by correlating between Sales.customerId and Customer.customerId, and from Customer.personId to get the Person.personId.
My question is whether I need to use an inner join or union, and how to use either of them to get the firstName and lastName of these customers
Union is mostly used for disjoint sets. To achieve your target, u can go with inner-join.
If you want to use joins, then here is the query which works similarly to your requirement.
SELECT TOP 10 S.CustomerID, P.FirstName,P.LastName, count(*)
FROM Sales S
INNER JOIN Customer C on S.CustomerId=C.CustomerId
INNER JOIN Person P on C.PersonId = P.PersonId
GROUP BY (S.CustomerID, P.FirstName,P.LastName)
ORDER BY count(*) DESC
You need use inner join like this :
SELECT TOP 10 S.CustomerID
, P.FirstName
, P.LastName
, COUNT (1) AS CountOfCustomer -- this is equal count(*)
FROM Sales S
INNER JOIN Customer C ON S.CustomerId = C.CustomerId
INNER JOIN Person P ON C.PersonId = P.PersonId
GROUP BY S.CustomerID, P.FirstName, P.LastName
ORDER BY 4 DESC; -- this is equal order by count(*)

Where clause removing calculations from my query SQL Server

I am having a trying to calculate a result set for myself but I am facing a strange problem where the WHERE clause is creating problems for me.
The table are as follows:-
Customer
CustomerId CustomerName
2 Jayesh
5 Hasan
SaleInvoiceMaster
CustomerId TotalInvoiceAmount
1 50000
PurchaseInvoiceMaster
CustomerId TotalInvoiceAmount
1 10000
PaymentTransactions
CustomerId PaymentAmount
1 10000
The result set that is working is as follows:-
SELECT DISTINCT C.CustomerId AS CustomerId, C.Name AS CustomerName, ISNULL(SIM.TotalSale, 0), ISNULL(PIM.TotalPurchase, 0), ISNULL(PT.TotalPaid, 0), ISNULL(SIM.TotalSale - PIM.TotalPurchase - PT.TotalPaid, 0) AS AmountPending
FROM Customers AS C
LEFT OUTER JOIN (SELECT CustomerId, ISNULL(SUM(TotalInvoiceAmount),0) AS TotalSale FROM SaleInvoiceMaster GROUP BY CustomerId) AS SIM ON SIM.CustomerId = C.CustomerId
LEFT OUTER JOIN (SELECT CustomerId, ISNULL(SUM(TotalInvoiceAmount),0) AS TotalPurchase FROM PurchaseInvoiceMaster GROUP BY CustomerId) AS PIM ON PIM.CustomerId = C.CustomerId
LEFT OUTER JOIN (SELECT CustomerId, PaymentStatus, ISNULL(SUM(PaymentAmount),0) AS TotalPaid FROM PaymentTransactions AS P GROUP BY CustomerId, PaymentStatus) AS PT ON PT.CustomerId = C.CustomerId
The result for the same is as shown in below image
Result Set
When I add a where clause at the end f the third left outer join, the problem arises. The calculation stops and it shows zero. My updated query is as follows:-
SELECT DISTINCT C.CustomerId AS CustomerId, C.Name AS CustomerName, ISNULL(SIM.TotalSale, 0), ISNULL(PIM.TotalPurchase, 0), ISNULL(PT.TotalPaid, 0), ISNULL(SIM.TotalSale - PIM.TotalPurchase - PT.TotalPaid, 0) AS AmountPending
FROM Customers AS C
LEFT OUTER JOIN (SELECT CustomerId, ISNULL(SUM(TotalInvoiceAmount),0) AS TotalSale FROM SaleInvoiceMaster GROUP BY CustomerId) AS SIM ON SIM.CustomerId = C.CustomerId
LEFT OUTER JOIN (SELECT CustomerId, ISNULL(SUM(TotalInvoiceAmount),0) AS TotalPurchase FROM PurchaseInvoiceMaster GROUP BY CustomerId) AS PIM ON PIM.CustomerId = C.CustomerId
LEFT OUTER JOIN (SELECT CustomerId, ISNULL(SUM(PaymentAmount),0) AS TotalPaid FROM PaymentTransactions AS PT1 WHERE (PT1.PaymentStatus = 'Payment Made' OR PT1.PaymentStatus = 'Bad Debt') GROUP BY CustomerId) AS PT ON PT.CustomerId = C.CustomerId
The result set becomes:-
Result denied
IN your main select body you are doing this:
ISNULL(SIM.TotalSale - PIM.TotalPurchase - PT.TotalPaid, 0) AS AmountPending
This is returning 0 if ANY of those columns are NULL, you want this instead:
ISNULL(SIM.TotalSale, 0) - ISNULL(PIM.TotalPurchase, 0) - ISNULL(PT.TotalPaid, 0) AS AmountPending
Or for more current syntax, use COALESCE instead of ISNULL:
COALESCE(SIM.TotalSale, 0) - COALESCE(PIM.TotalPurchase, 0) - COALESCE(PT.TotalPaid, 0) AS AmountPending
You are have several confusions in the query. First, you don't need select distinct in the outermost query. Second, there is a difference between a subquery returning no matching rows and a NULL value in the subquery. Third, you are adding potentially NULL values together.
An improved version of the query:
SELECT C.CustomerId, C.Name AS CustomerName,
COALESCE(SIM.TotalSale, 0) as TotalSale,
COALESCE(PIM.TotalPurchase, 0) as TotalPurchase,
COALESCE(PT.TotalPaid, 0) as TotalPaid,
(COALESCE(SIM.TotalSale, 0) - COALESCE(PIM.TotalPurchase, 0)
- COALESCE(PT.TotalPaid, 0)
) as AmountPending
FROM Customers C LEFT OUTER JOIN
(SELECT CustomerId, SUM(TotalInvoiceAmount) AS TotalSale
FROM SaleInvoiceMaster
GROUP BY CustomerId
) SIM
ON SIM.CustomerId = C.CustomerId LEFT OUTER JOIN
(SELECT CustomerId, SUM(TotalInvoiceAmount) AS TotalPurchase
FROM PurchaseInvoiceMaster
GROUP BY CustomerId
) PIM
ON PIM.CustomerId = C.CustomerId LEFT OUTER JOIN
(SELECT CustomerId, SUM(PaymentAmount) AS TotalPaid
FROM PaymentTransactions PT1
WHERE PT1.PaymentStatus IN ('Payment Made', 'Bad Debt')
GROUP BY CustomerId
) PT
ON PT.CustomerId = C.CustomerId;
Removing the SELECT DISTINCT improves performance and makes the query more readable. Assuming CustomerId is unique in Customers, duplicates cannot be created.
Removing the ISNULL() in the subqueries makes the query more readable. This operation does nothing, because the NULLs need to be handled after the JOIN.
Replacing the OR with IN make the query more readable.

Rows with highest values from second and third tables

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

select count over partition by

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.

only 1 value returns with sql query

AdventureWorks2012 DB - I am trying to return top 1 or 2 emlpoyees from Finance dept and Engineer dept who have worked longest. I cant get my query to return both, only results from engineering show. Any suggestions?
SELECT TOP 2 EDH.StartDate, E.BusinessEntityID, D.Name, EDH.EndDate, DATEDIFF(hour,EDH.StartDate, GETDATE()) AS HoursWorked
FROM HumanResources.Employee E
INNER JOIN Person.Person PP ON E.BusinessEntityID = PP.BusinessEntityID
INNER JOIN HumanResources.EmployeeDepartmentHistory EDH ON E.BusinessEntityID = EDH.BusinessEntityID
INNER JOIN HumanResources.Department D ON D.DepartmentID = EDH.DepartmentID
WHERE (D.Name LIKE 'Finance' OR D.Name = 'Engineering')
AND EDH.EndDate IS NULL
GROUP BY D.Name, EDH.StartDate,E.BusinessEntityID,EDH.EndDate
ORDER BY EDH.StartDate ASC
Your problem is that the employees from Engineering happen to have started before the employees from Finance. The ORDER BY is affecting all of your records (both departments), and then the TOP 2 value is grabbing the two most recent employees, regardless of departments.
If you are trying to write a query that returns the first employee from each department, you're going to have to get a bit more complex. Here is an example that uses the ROW_NUMBER() function to order employees within each department by their start date, then filters those records to only return employees who are the first individuals in their department.
SELECT
StartDate,
BusinessEntityID,
Name,
EndDate,
HoursWorked
FROM
(
SELECT
EDH.StartDate,
E.BusinessEntityID,
D.Name,
EDH.EndDate,
DATEDIFF(hour,EDH.StartDate, GETDATE()) AS HoursWorked,
ROW_NUMBER() OVER (PARTITION BY D.Name ORDER BY EDH.StartDate) AS RowNumberWithinDepartment
FROM
HumanResources.Employee E
INNER JOIN
Person.Person PP ON E.BusinessEntityID = PP.BusinessEntityID
INNER JOIN
HumanResources.EmployeeDepartmentHistory EDH ON E.BusinessEntityID = EDH.BusinessEntityID
INNER JOIN
HumanResources.Department D ON D.DepartmentID = EDH.DepartmentID
WHERE
(D.Name LIKE 'Finance' OR D.Name = 'Engineering') AND
EDH.EndDate IS NULL
GROUP BY D.Name, EDH.StartDate,E.BusinessEntityID,EDH.EndDate
) x
WHERE RowNumberWithinDepartment = 1
ORDER BY StartDate ASC

Resources