Identify duplicate values when using JOIN in Microsoft Access - sql

I have 2 tables that hold values for customers. The first table holds the names of the customer and the second holds information relating to the customer such as transactions.
The first table looks like
CustomerID Name
1 Joe
2 Jane
The second table looks like
TransactID CustomerID Reference
1 1 REF123
2 2 REF123
3 1 REF321
I need to able to identify all duplicates in the reference column as well as the customer it belongs to e.g. Joe, Jane
The code i have at the moment looks like
SELECT o.name, COUNT(p.reference) as RefCount
FROM (t_cust as o
INNER JOIN t_custprop as p
ON o.customerid = p.customerid)
GROUP BY o.name, p.reference
HAVING (COUNT(p.reference)>1)
ORDER BY o.name ASC
As i don't know the possible values that may be duplicates, the code above doesn't return the name of the customer and the reference that may be a duplicate.

Grouping by the item you're counting will always result in the count being 1, which is eliminated by your having clause. This should to the trick:
SELECT o.name, p.reference
FROM t_cust o
INNER JOIN t_custprop p ON o.customerid = p.customerid
WHERE p.reference IN (
SELECT p2.reference
FROM t_custprop p2
GROUP BY p2.reference
HAVING COUNT(p2.customerid) > 1
)
ORDER BY o.name ASC

Related

Return unique row only - TSQL

I have a customer table and order tables. In customer table we have 'Family link' column which is a given ID to each customer. e.g. familyLink: A121, if this customer has a family member in the table they will have this ID too : A121. Basically I need to return all customers with no family members and have made an order_number 2 or 3
Customer table:
CustmID(PK), Name(varchar), familyLink(varchar).
Order table:
OrderID(PK), order_number (varchar), CustmID(FK)
The query I've return which didn't seem to return customers with no family member..
Select Distinct
c.familyLink,
c.name,
o.order_number
From
Customer c
Left join
Order o on c.CustmID = o.CustmID
where
(o.order_number = 2 or order_number=3)
Examples:
Customer table
Custm ID Name FamilyLink
C1 Liam A11
C2 Lucy A12
C3 David A11
C4 Suzy A13
Orders table
OrderID Order_Number CustmID
O1 2 C1
O2 3 C2
O3 2 C4
Results`
This query should return Lucy and Suzy because they don't have any family members in the customer table..
Any idea why this is returning customers who share familyLink?
Any help appreciated.
Any idea why this is returning customers who share familyLink ?
Because nothing in your query is limiting it to that. You're asking for all rows where you the o.order_number = 2 or order_number = 3; there's nothing about "not returning customers that don't have a family link".
You also have a syntax error in your SQL, specifically Left join Order. ORDER is a Reserved Keyword in SQL Server, and in most (if not every) SQL language. It is strongly advised that you do not give objects names that are a Reserved keyword or a Future Keyword. If you do have an object that has an Reserved Keyword for a name, you must quote it: [Order].
As for what you are after, this is a total guess, but perhaps:
WITH CTE AS(
SELECT C.familyLink,
C.name,
O.order_number,
COUNT(C.CustmID) OVER (PARTITION BY O.order_number) AS Customers
FROM Customer C
INNER JOIN [Order] O ON C.CustmID = O.CustmID --This is an INNER JOIN, as the WHERE must be met, so there can never not be a row
WHERE O.order_number IN (2,3))
SELECT C.familyLink,
C.name,
C.order_number
FROM CTE
WHERE Customers = 1;
If this doesn't work, you'll need to provide sample data and expected results. I put this an answer, however, as my opening statements were also far too long for a comment.

How to fix sql query problem with two or more position which have one ID

I have sql query where I have to join three tables. One of this is a table with data of invoice, it looks like this:
INVOICE
ID CUSTOMER_NAME TAXID NUMBER LABEL GUID
1 CUSTOMER1 8739281100 FV001/2019 1 04EABFB3-0B9D-4749-B99D-A4EBEE079633
POSITION OF INVOICE
ID ID_INV POSITION_NAME COUNT
1 1 NAME1 3
2 1 NAME2 2,5
TABLE WITH LABEL
ID NAME VALUE GUID_INV
1 LABEL1 true 04EABFB3-0B9D-4749-B99D-A4EBEE079633
When I want to run this query I have statement like this multiple rows in singleton select.
This is for Firebird 2.5.
SELECT
a.ID,
a.GUID,
a.NUMBER,
a.CUSTOMER_NAME,
b.COUNT,
(select usrd.LABEL from USER_FIELD_DEFS usrd
where usrd.GUID_INV=a.GUID and (usrd.ID=1 and usrb.VALUE='true')) as LABEL_NAME
FROM INVOICE a
join POSITION_INVOICE b ON a.ID=b.ID_INV
I want to get result like this
1 04EABFB3-0B9D-4749-B99D-A4EBEE079633 FV001/2019 CUSTOMER1 3 LABEL1
1 04EABFB3-0B9D-4749-B99D-A4EBEE079633 FV001/2019 CUSTOMER1 2,5 LABEL1
Please help with this. I know that solution maybe is very simple but I have some eclipse of the mind:)
This should give you the rows you want based on the 3 tables you provided. If there is a chance that an invoice has no position then simply replace the inner join with left join
SELECT
I.[Id]
,I.[GUID]
,I.[NUMBER]
,I.[CUSTOMER_NAME]
,IP.[POSITION_NAME]
,L.[NAME]
FROM [INVOICE] I
INNER JOIN [IN_P] IP ON IP.ID_INV = I.Id
LEFT JOIN [LABEL] L ON L.[GUID_INV] = I.[GUID]
You are just missing one more join here. Assuming USER_FIELD_DEFS is the same as TABLE WITH LABEL that you have mentioned here
SELECT
a.ID,
a.GUID,
a.NUMBER,
a.CUSTOMER_NAME,
b.COUNT,
c.NAME
FROM INVOICE a
JOIN POSITION_INVOICE b ON a.ID=b.ID_INV
JOIN USER_FIELD_DEFS c ON c.GUID_INV = a.GUID AND c.ID=1 and c.VALUE='true'

SQL Query Count - Join two tables and get a count even if it is 0

Ok, working on a query in SQL 2012 right now to join two tables and get a count. The count is how many companies are associated with a primary company. This lists exists in the same table, Contact, and they are all connected as ID of the primary company is listed in the secondary company as CompanyID. I can get a count if the primary has at least 1 secondary but I can't seem to get a count if the primary has no secondary and I need to show that 0 value. Here is my SQL query:
SELECT c.ID, c.Company, c.Category, COUNT(c1.ID) AS Secondaries
FROM Contact AS c INNER JOIN Contact AS c1 ON c.ID = c1.CompanyId
WHERE (c.MemberType = 'ORG_M') AND (c1.MemberType = 'ORG_M')
GROUP BY c.ID, c.Company, c.Category
When I do this, I get this information back:
ID Company Category Count
1 Company 1 RS_1 1
2 Company 2 RS_1 1
3 Company 3 RS_1 1
4 Company 4 RS_1 1
What I am missing is the 0 value for if a company exists in the company table but has no secondary company tied to them. How do I get that?
Use an outer join instead and move the where criteria to the join:
SELECT c.ID, c.Company, c.Category, COUNT(c1.ID) AS Secondaries
FROM Contact AS c
LEFT JOIN Contact AS c1 ON c.ID = c1.CompanyId AND c1.MemberType = 'ORG_M'
WHERE c.MemberType = 'ORG_M'
GROUP BY c.ID, c.Company, c.Category

Selecting from table with categories of people

I created a database in ms sql , in the database I have three category of persons namely staff, customers, suppliers whom I stored in different tables create serial unique id for each.
Now these persons id are stored under person_id and a column names person type which stores whether its a staff, custimer or supplier in the transaction table, The problem lies in selecting the records from the transaction table like this pseudo code
Select t.*,s.na as staff,sp.name as supplier, c.name as customer
From Trans t
left join Staff s on s.id = t.pid
left join Suppliers sp on sp.id = t.pid
left join Customers c on c.id = t.pid
This returns one row, instead of at least 3 or more, How do I solve this problem
My trans table
person_id Person_type Trans_id
1 staff 1
1 customer 2
2 customer 3
3 suppler 4
1 staff 5
Expected output
person_name Trans_id
james 1
mark 2
dan 3
jude 4
james 5
Staff, Customers, and suppliers are stored in their different tables
That's what the Join does, combine data from multiple tables into one result row. If you want to "keep the rows", not combine them, you can use UNION
(
Select t.* From Trans t
left join Staff s on s.id = t.pid
)
UNION
(
Select t.* From Trans t
left join Suppliers sp on sp.id = t.pid
)
UNION
(
Select t.* From Trans t
left join Customers c on c.id = t.pid
)
This will get you the multiple rows you want BUT still not sure you have defined it right. I see you are only taking columns from Trans, so you're not getting any data from the other tables. And you're doing left outer joins so the other tables won't affect the selection. So I think it's just that same as selecting from just Trans.
If what you want is data from Trans where there is corresponding entry in the other tables, then do the UNION, but also change the outer joins to inner.

In SQL how do I write a query to return 1 record from a 1 to many relationship?

Let's say I have a Person table and a Purchases table with a 1 to many relationship. I want to run a single query that returns this person and just their latest purchase. This seems easy but I just can't seem to get it.
select p.*, pp.*
from Person p
left outer join (
select PersonID, max(PurchaseDate) as MaxPurchaseDate
from Purchase
group by PersonID
) ppm
left outer join Purchase pp on ppm.PersonID = pp.PersonID
and ppm.MaxPurchaseDate = pp.PurchaseDate
where p.PersonID = 42
This query will also show the latest purchase for all users if you remove the WHERE clause.
Assuming you have something like a PurchaseDate column and want a particular person (SQL Server):
SELECT TOP 1 P.Name, P.PersonID, C.PurchaseDescription FROM Persons AS P
INNER JOIN Purchases AS C ON C.PersonID = P.PersonID
WHERE P.PersonID = #PersonID
ORDER BY C.PurchaseDate DESC
Many Databases preform the "Limit or Top" command in different ways. Here is a reference http://troels.arvin.dk/db/rdbms/#select-limit and below are a few samples
If using SQL Server
SELECT TOP 1
*
FROM Person p
INNER JOIN Purchases pc on pc.PersonID = P.PersonID
Order BY pc.PurchaseDate DESC
Should work on MySQL
SELECT
*
FROM Person p
INNER JOIN Purchases pc on pc.PersonID = P.PersonID
Order BY pc.PurchaseDate DESC
LIMIT 1
Strictly off the top of my head!...If it's only one record then...
SELECT TOP 1 *
FROM Person p
INNER JOIN Purchases pu
ON p.ID = p.PersonId
ORDER BY pu.OrderDate
WHERE p.ID = *thePersonYouWant*
otherwise...
SELECT TOP 1 *
FROM Person p
INNER JOIN
(
SELECT TOP 1 pu.ID
FROM Purchases pu
ON pu.PersonID = p.Id
ORDER BY pu.OrderDate
) sq
I think! I haven't got access to a SQL box right now to test it on.
Without knowing your structure at all, or your dbms, you would order the results descending by the purchase date/time, and return only the first joined record.
Try TOP 1 With an order by desc on date. Ex:
CREATE TABLE #One
(
id int
)
CREATE TABLE #Many
(
id int,
[date] date,
value int
)
INSERT INTO #One (id)
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3
INSERT INTO #Many (id, [date], value)
SELECT 1, GETDATE(), 1 UNION ALL
SELECT 1, DATEADD(DD, 1 ,GETDATE()), 3 UNION ALL
SELECT 1, DATEADD(DD, -1 ,GETDATE()), 0
SELECT TOP 1 *
FROM #One O
JOIN #Many M ON O.id = M.id
ORDER BY [date] DESC
If you want to select the latest purchase for each person, that would be:
SELECT PE.ID, PE.Name, MAx(PU.pucrhaseDate) FROM Persons AS PE JOIN PURCHASE as PU ON PE.ID = PU.Person_ID
If you want to have all persons also those who have no purchases, you need to use LEFT JOIN.
I think you need one more table called Items for example.
The PERSONS table would uniquely define each person and all their attributes, while the ITEMS table would uniquely define each items and their attributes.
Assume the following:
Persons |Purchases |Items
PerID PerName |PurID PurDt PerID ItemID |ItemID ItemDesc ICost
101 Joe Smith |201 101107 101 301 |301 Laptop 500
|202 101107 101 302 |302 Desktop 699
102 Jane Doe |203 101108 102 303 |303 iPod 199
103 Jason Tut |204 101109 101 304 |304 iPad 499
|205 101109 101 305 |305 Printer 99
One Person Parent may tie to none, one or many Purchase Child.
One Item Parent may tie to none, one or many Purchase Child.
One or more Purchases Children will tie to one Person Parent, and one Item Parent.
select per.PerName as Name
, pur.PurDt as Date
, itm.ItemDesc as Item
, itm.ICost as Cost
from Persons per
, Purchases pur
, Items itm
where pur.PerID = per.PerID -- For that Person
and pur.ItemID = itm.ItemID -- and that Item
and pur.PurDt = -- and the purchase date is
( Select max(lst.PurDt) -- the last date
from Purchases lst -- purchases
where lst.PerID = per.PerID ) -- for that person
This should return:
Name Date Item Cost
Joe Smith 101109 Ipad 499
Joe Smith 101109 Printer 99
Jane Doe 101108 iPod 199