Getting duplicate rows after two JOINS and a UNION command - sql

I have 3 tables in the following way:
Client with a client id
Cards with a card id and a FK with client id
Transactions with a transaction id and a FK with Card id
Every client can have more than a card, and a card can make more than a transaction.
I want to do the following: Obtain the 3 clients with the minor number of transactions.
My problem: my query returns a client 2 times.
SELECT TOP 3
ClientId, Name, LastName, QtyTrans
FROM
(SELECT
ClientId, Name, LastName, 0 AS QtyTrans
FROM
Client
JOIN
Card ON ClientId = IdClient
WHERE
CardId NOT IN (SELECT CardId FROM Transaction)
GROUP BY
ClientId, Name, LastName
UNION
SELECT
ClientId, Name, LastName, COUNT(TransId) AS QtyTrans
FROM
Client
JOIN
Card c ON ClientId = IdClient
JOIN
Transaction t ON c.CardId = t.CardId
GROUP BY
ClientId, Name, LastName
) TotalTrans
ORDER BY
QtyTrans
When the client has transactions with every card, just returns one row, but if one of the cards has no transactions returns one row with the count 0 and another one with the sum of the other cards transactions.
Result:
11 Martin Camejo 0,
7 Matias Barrenechea 0,
7 Matias Barrenechea 2
Any help?

I want to do the following: Obtain the 3 clients with the minor number of transactions.
I don't see what UNION has to do with this question. You just want LEFT JOIN and GROUP BY:
SELECT TOP (3) cl.ClientId, cl.Name, cl.LastName,
COUNT(t.CardId) AS QtyTrans
FROM Client cl LEFT JOIN
Card c
ON cl.ClientId = c.IdClient LEFT JOIN -- don't know which table has which column
Transaction t
ON t.CardId = c.CardId
GROUP BY cl.ClientId, cl.Name, cl.LastName
ORDER BY QtyTrans ASC;

Related

Need SQL MAX please

I have a table with a list of Client No's, ID etc & there are many Clients with different ID's. I need to pull out the MAX ID No. for each Client, e.g.
ClientNo: 1500 has 3 ID's - the maximum in the ID field is the one I need!
UPDATE: This works:
SELECT MP.ClientID, MP.SequenceID
FROM TABLENAME MP
INNER JOIN (
SELECT ClientID, MAX(SequenceID) SequenceID
FROM TABLENAME
GROUP BY ClientID
) b on MP.ClientID = b.ClientID AND MP.SequenceID = b.SequenceID
BUT....
I need to link the table to many others to pull in other data, where do I insert the left joins to these tables please?
I am assuming you have multiple same client (numbers) with different IDs and for each client (number) you have to get the maximum ID. You may do the following:
select client_number, max(ID) from client group by client_number;
Depending on your need tweak this query.
You may want to do this:
SELECT MP.ClientID, b.DesiredValue
FROM TABLENAME MP
INNER JOIN (
SELECT ClientID, DesiredValue, ROW_NUMBER () OVER (PARTITION BY ClientID order by SequenceID desc) As RecentRN
FROM TABLENAME
) b
on MP.ClientID = b.ClientID AND b.RecentRN = 1
or
SELECT MP.ClientID, b.DesiredValue
FROM TABLENAME MP
INNER JOIN (
SELECT ClientID, DesiredValue,ROW_NUMBER () OVER (PARTITION BY ClientID order by SequenceID desc) As RecentRN
FROM TABLENAME
) b
on MP.ClientID = b.ClientID
Where b.RecentRN = 1

SQL Join Multiple Tables and get the first row

I have a database where there are customers, phones, and addresses. Customers can have multiple phones and addresses and each phone and address record has a corresponding CustID. I'm trying to join these three tables and grab one phone and one address per customer, but cannot get this to work. The query returns one phone number per customer, but still return multiple addresses.
Here is my query:
SELECT customer_set.ID,
phone_set.cphone,
customer_set.Name,
address_set.Number,
address_set.Street
FROM (
SELECT ID, Name FROM CUSTOMER
) AS customer_set
LEFT JOIN PHONE AS phone_set
ON phone_set.CustID = (SELECT TOP 1 CustID
FROM PHONE
WHERE CustID = customer_set.ID
ORDER BY IsPrimary DESC)
LEFT JOIN ADDRESS AS address_set
ON address_set.CustID = (SELECT TOP 1 CustID
FROM ADDRESS
WHERE CustID = customer_set.ID
ORDER BY IsPrimary DESC)
Here you go:
SELECT
data.ID,
data.cphone,
data.Name,
data.Number,
data.Street
FROM (SELECT
customer_set.ID,
phone_set.cphone,
customer_set.Name,
address_set.Number,
address_set.Street,
ROW_NUMBER() OVER (PARTITION BY customer_set.ID ORDER BY customer_set.Name ASC) AS RowNum
FROM customer_set
LEFT OUTER JOIN PHONE
ON PHONE.CustID = customer_set.ID
LEFT OUTER JOIN ADDRESS
ON ADDRESS.CustID = customer_set.ID) AS data
WHERE data.RowNum = 1

How to filter out duplicate records caused by a JOIN in SQL?

I have a simple query that returns a list of phone numbers for a given customer. The users are able to search for a specific customer by entering any part of their address. The customer can have multiple phone numbers and addresses.
Here is an example of my query:
SELECT
ROW_NUMBER() OVER(PARTITION BY Customer.CustomerNumber, ORDER BY PhoneNumber.PhoneNumber) RowNumber,
Customer.CustomerNumber,
PhoneNumber.PhoneNumber
FROM Customer
JOIN PhoneNumber ON PhoneNumber.CustomerId = Customer.Id
JOIN CustomerAddress on CustomerAddress.CustomerId = Customer.Id
Here is what this query is producing when I have a customer that has two phone numbers and two addresses:
RowNumber CustomerNumber PhoneNumber
1 1 111-111-1111
2 1 222-222-2222
3 1 111-111-1111
4 1 222-222-2222
My desired result would be something along these lines:
RowNumber CustomerNumber PhoneNumber
1 1 111-111-1111
2 1 222-222-2222
I can only produce the desired result above when I remove the join on the address table.
A user should be able to look up a customer by entering in any part of the address (ex: I want to show any user that has an address in Phoenix). While it isn't displayed in the result, it still should be filterable.
I think I am able to do something like this:
SELECT *, ROW_NUMBER() OVER(PARTITION BY Test.CustomerNumber ORDER BY Test.PhoneNumber) RowNumber
FROM
(
SELECT
DISTINCT
CustomerNumber,
PhoneNumber.PhoneNumber
FROM Customer
JOIN PhoneNumber ON PhoneNumber.CustomerId = Customer.Id
JOIN CustomerAddress ON CustomerAddress.CustomerId = Customer.Id
) Test
You're not selecting any columns from the CustomerAddress table, so joining that table has only the effects of suppressing results for customers with no address and duplicating results for those with multiple addresses.
If you don't want either of those effects then don't join CustomerAddress. If you want only the former then you'd be better off with a different approach, such as
SELECT
ROW_NUMBER() OVER(PARTITION BY Customer.CustomerNumber,
ORDER BY PhoneNumber.PhoneNumber) RowNumber,
Customer.CustomerNumber,
PhoneNumber.PhoneNumber
FROM
Customer
JOIN PhoneNumber ON PhoneNumber.CustomerId = Customer.Id
WHERE
Customer.Id IN (SELECT CustomerId from CustomerAddress)
Presuming that Customer.Id is a primary key, that should produce duplicates only if duplicate phone numbers for a given customer are recorded in the PhoneNumber table.
Removing the join on address might affect the ability of users to search by address. If that is the problem, change the query to use exists:
SELECT ROW_NUMBER() OVER (PARTITION BY c.CustomerNumber ORDER BY pn.PhoneNumber) as RowNumber,
c.CustomerNumber,
pn.PhoneNumber
FROM Customer c JOIN
PhoneNumber pn
ON pn.CustomerId = c.Id
WHERE EXISTS (SELECT 1
FROM CustomerAddress ca
WHERE ca.CustomerId = c.Id AND
ca.address like '%#ADDRESS%' -- this is just an example of searching logic
);
Change your window function to partition by customer and phone number in a sub query. I use this all the time to filter dupes. Just set the partition by to your unique key.
Select * from (
SELECT
ROW_NUMBER() OVER(PARTITION BY Customer.CustomerNumber, PhoneNumber PhoneNumber, ORDER BY PhoneNumber.PhoneNumber) RowNumber,
Customer.CustomerNumber,
PhoneNumber.PhoneNumber
FROM Customer
JOIN PhoneNumber ON PhoneNumber.CustomerId = Customer.Id
JOIN CustomerAddress on CustomerAddress.CustomerId = Customer.Id)
Where RowNumber = 1

Two group by tables stich another table

I have 3 tables I need to put together.
The first table is my main transaction table where I need to get distinct transaction id numbers and company id. It has all the important keys. The transaction ids are not unique.
The second table has item info which is linked to transaction id numbers which are not unique and I need to pull items.
The third table has company info which has company id.
Now I've sold some of these with the first one through a group by id. The second through a subquery which creates unique ids and joins onto the first one.
The issue I'm having is the third one by company. I cannot seem to create a query that works in the above combinations. Any ideas?
As suggested here is my code. It works but that's because for the company I used count which doesn't give the correct number. How else can I get the company number to come out correct?
SELECT
dep.ItemIDAPK,
dep.TotalOne,
dep.company,
company.vendname,
appd.ItemIDAPK,
appd.ItemName
FROM (
SELECT
csi.ItemIDAPK,
sum(f.TotalOne) as TotalOne,
count(f.DimCurrentcompanyID) company
FROM dbo.ReportOne F with (nolock)
INNER JOIN dbo.DSaleItem csi with (nolock)
on f.DSaleItemID = csi.DSaleItemID
INNER JOIN dbo.DimCurrentcompany cv
ON f.DimCurrentcompanyID = cv.DimCurrentcompanyID
INNER JOIN dbo.DimDate dat
on f.DimDateID = dat.DimDateID
where (
dat.date >='2013-01-29 00:00:00.000'
and dat.date <= '2013-01-30 00:00:00.000'
)
GROUP BY csi.ItemIDAPK
) as dep
INNER JOIN (
SELECT
vend.DimCurrentcompanyID,
vend.Name vendname
FROM dbo.DimCurrentcompany vend
) As company
on dep.company = company.DimCurrentcompanyID
INNER JOIN (
SELECT
c2.ItemIDAPK,
ItemName
FROM (
SELECT DISTINCT ItemIDAPK
FROM dbo.dimitem AS C
) AS c1
JOIN dbo.dimitem AS c2 ON c1.ItemIDAPK = c2.ItemIDAPK
) as appd
ON dep.ItemIDAPK = appd.ItemIDAPK
For further information my output is the following example, I know the code executes and the companyid is incorrect as I just put it with a (count) in their to make the above code execute:
Current Results:
Item Number TLS CompanyID Company Name Item Number Item Name
111111 300 303 Johnson Corp 29323 Soap
Proposed Results:
Item Number TLS CompanyID Company Name Item Number Item Name
111111 300 29 Johnson Corp 29323 Soap

SQL - Select highest value when data across 3 tables

I have 3 tables:
Person (with a column PersonKey)
Telephone (with columns Tel_NumberKey, Tel_Number, Tel_NumberType e.g. 1=home, 2=mobile)
xref_Person+Telephone (columns PersonKey, Tel_NumberKey, CreatedDate, ModifiedDate)
I'm looking to get the most recent (e.g. the highest Tel_NumberKey) from the xref_Person+Telephone for each Person and use that Tel_NumberKey to get the actual Tel_Number from the Telephone table.
The problem I am having is that I keep getting duplicates for the same Tel_NumberKey. I also need to be sure I get both the home and mobile from the Telephone table, which I've been looking to do via 2 individual joins for each Tel_NumberType - again getting duplicates.
Been trying the following but to no avail:
-- For HOME
SELECT
p.PersonKey, pn.Phone_Number, pn.Tel_NumberKey
FROM
Persons AS p
INNER JOIN
xref_Person+Telephone AS x ON p.PersonKey = x.PersonKey
INNER JOIN
Telephone AS pn ON x.Tel_NumberKey = pn.Tel_NumberKey
WHERE
pn.Tel_NumberType = 1 -- e.g. Home phone number
AND pn.Tel_NumberKey = (SELECT MAX(pn1.Tel_NumberKey) AS Tel_NumberKey
FROM Person AS p1
INNER JOIN xref_Person+Telephone AS x1 ON p1.PersonKey = x1.PersonKey
INNER JOIN Telephone AS pn1 ON x1.Tel_NumberKey = pn1.Tel_NumberKey
WHERE pn1.Tel_NumberType = 1
AND p1.PersonKey = p.PersonKey
AND pn1.Tel_Number = pn.Tel_Number)
ORDER BY
p.PersonKey
And have been looking over the following links but again keep getting duplicates.
SQL select max(date) and corresponding value
How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
SQL Server: SELECT only the rows with MAX(DATE)
Am sure this must be possible but been at this a couple of days and can't believe its that difficult to get the most recent / highest value when referencing 3 tables. Any help greatly appreciated.
select *
from
( SELECT p.PersonKey, pn.Phone_Number, pn.Tel_NumberKey
, row_number() over (partition by p.PersonKey, pn.Phone_Number order by pn.Tel_NumberKey desc) rn
FROM
Persons AS p
INNER JOIN
xref_Person+Telephone AS x ON p.PersonKey = x.PersonKey
INNER JOIN
Telephone AS pn ON x.Tel_NumberKey = pn.Tel_NumberKey
WHERE
pn.Tel_NumberType = 1
) tt
where tt.rn = 1
ORDER BY
tt.PersonKey
you have to use max() function and then you have to order by rownum in descending order like.
select f.empno
from(select max(empno) empno from emp e
group by rownum)f
order by rownum desc
It will give you all employees having highest employee number to lowest employee number. Now implement it with your case then let me know.