How to select from more than one record of the same field in a JOIN - sql

I have a table of letters. And table with authors and recipients called "people". I want to run a SQL command that returns a table or row with the letter and BOTH its author and its recipient.
Here's what I tried so far. If I need a table with letters and the author name I can use:
SELECT date, type, description, firstName, lastName
FROM letters
INNER JOIN people ON letters.authorId=people.ROWID
This gives me a table like the following:
1866-12-08 request need of women and children, list of needed supplies, FREEDMEN'S BUREAU A.M.L. Crawford
1867-01-18 request destitution of women and children in state and efforts to help M.H. Cruikshank
If I need recipient I can change the last line to:
INNER JOIN people ON letters.recipientId=people.ROWID
I want both the author and recipient. But I cannot seem to select more than one of the same field in a JOIN.
I have tried using the following.
SELECT date, type, description, firstName, lastName, firstName, lastName
FROM letters
INNER JOIN people ON letters.authorId=people.ROWID
INNER JOIN people ON letters.recipient=people.ROWID
This leads to the error:
Execution finished with errors.
Result: ambiguous column name: firstName
At line 1:
SELECT date, type, description, firstName, lastName, firstName, lastName
FROM letters
INNER JOIN people ON letters.authorId=people.ROWID
INNER JOIN people ON letters.recipient=people.ROWID

When you JOIN to the same table more than once, as you do to show senders' and recipients' details, you must give the tables aliases.
FROM letters
INNER JOIN people senders ON letters.authorId=senders.ROWID
INNER JOIN people recips ON letters.recipient=recips.ROWID
Then you can mention columns from senders and recips in SELECT, WHERE, and other clauses as if those were separate tables.
SELECT letter.date, letter.type, letter.description,
sender.firstName, sender.lastName,
recip.firstName, recip.lastName
...
Pro tip In queries with JOINs, always qualify each column you mention with the table name or alias. Say, for example, letter.description instead of just description. It makes your query much easier to understand for the next person. or even your future self.

Related

Find potential duplicate names in database

I have two tables in a SQL Server Database:
Table: People
Columns: ID, FirstName, LastName
Table: StandardNames
Columns: Nickname, StandardName
Sample Nicknames would be Rick, Rich, Richie when StandardName is Richard.
I would like to find duplicate contacts in my People table but replace any of the nicknames with the standard name. IE: sometimes I have Rich Smith other times it is Richard Smith in the People table. Is this possible? I realize it might be multiple joins to the same table but can't figure out how to start.
Firstly, you need to determine how many duplicates you have in your People table...
SELECT p.FirstName, COUNT(*)
FROM People AS p
INNER JOIN StandardNames AS sn
ON CHARINDEX(sn.Nickname, p.FirstName) > 0 OR
CHARINDEX(sn.Nickname, p.LastName) > 0
GROUP BY p.FirstName
HAVING COUNT(*) > 1
That's just to get an idea of what data you're trying to find in relation to the Nicknames that may possibly exist inside (as a wildcard word search) the Firstname and Lastname columns.
If you are happy with the items found then expand on the query to update the values.
Let's say you wanted to change the Firstname to be the Standardname...
UPDATE p2
SET p2.FirstName = p2.Standardname
FROM
(SELECT p.ID, sn.StandardName
FROM People AS p
INNER JOIN StandardNames AS sn
ON CHARINDEX(sn.Nickname, p.FirstName) > 0 OR
CHARINDEX(sn.Nickname, p.LastName) > 0) AS a
INNER JOIN People AS p2 ON p2.ID = a.ID
So this will obviously find all the People IDs that have a match based on the query above, and it will update the People table by replacing the FirstName with the StandardName.
However, there are issues with this due to the limitation of your question.
the StandardNames table should have its own ID field. All tables should have an ID column as its primary table. That's just my view.
this is only going to work for data it matches using the CHARINDEX() function. What you really need is something to find based on a "sound" or similarity to the nicknames. Check out the SOUNDEX() function and apply your logic from there.
And this is assuming your IDs above are unique!
Good luck
You could standardize the names by joining, and count the number of occurrences. Extracting the ID is a bit fiddly, but also quite possible. I'd suggest the following - use a case expression to find the contact with the standard name, and if you don't have one, just take the id of the first duplicate:
SELECT COALESCE(MIN(CASE FirstName WHEN StandardName THEN id END), MIN(id)),
StandardName,
LastName,
COUNT(*)
FROM People p
LEFT JOIN StandardNames s ON FirstName = Nickname AND
GROUP BY StandardName, LastName

SQL Statement querying same table 2 times

Ok, I've got brain cells melting at an alarming rate on this SQL statement. Not my database, but I've been tasked with extracting data. So here's what I'm dealing with...
It is medical data. We have a database where ALL of the people are listed in one table- patients, as well as doctors. Each person has a unique PersonID. Let's just start with the Person table:
Person:
PersonID, PersonType, LastName, FirstName
I have another table that is hospital admissions.
Admissions:
AdmissionID, PersonID and PrimaryMD
where the Primary MD is the same as the Person ID for a doctor.
I need to extract each Admission, with the last name, and then the first name of the patient, but then I need to go back, based on the PrimaryMD identifier and use that value to pull the last name and first name of the doctor so that my results look like:
Admission | PatientLastName | PatientFirstName | DoctorLastName | DoctorFirstName
Ultimately, I'll need to pull address information for both the patient, and the doctor which is all stored in an address table with the same PersonID as in the person table, and then pull the doctor's address using the primarymd against the person table. But I can't figure how to write two queries in the same statement against these similar columns. I tried using aliases, and some left and inner joins and even a union, but I can't seem to get things right.
Any assistance would be hugely appreciated.
Try this:
SELECT
a.AdmissionID,
pat.LastName AS PatientLastName,
pat.FirstName AS PatientFirstName,
doc.LastName AS DoctorLastName,
doc.FirstName AS DoctorFirstName
FROM Admissions a
INNER JOIN Person pat
ON a.PersonID = pat.PersonID
INNER JOIN Person doc
ON a.PrimaryMD = doc.PersonID
For getting addresses use the same steps:
SELECT
a.AdmissionID,
pat.LastName AS PatientLastName,
pat.FirstName AS PatientFirstName,
doc.LastName AS DoctorLastName,
doc.FirstName AS DoctorFirstName
FROM Admissions a
INNER JOIN Person pat
ON a.PersonID = pat.PersonID
INNER JOIN Person doc
ON a.PrimaryMD = doc.PersonID
INNER JOIN Addresses addPat
ON pat.PersonID = addPat.PersonID
INNER JOIN Addresses addDoc
ON doc.PersonID = addDoc.PersonID

Join a SQL resultset based on common email address

I have one table that contains both students and parents records. There is a common field (email address) in both parent and student records that match the records (parents and students have the same email address).
I want my query to find the common email addresses and return each
student record but it must also include a field (Mifare) from the
parents record.
So I have tried to join and where clauses but i am getting crazy results. I was also thinking of using the with clause.
Expected result is
The basic script is:
Select extid, first_name, last_name, commonemail, designation,mifare
from students
Please assist with a basic coding - no procedures etc...just simple help for a newbie!
Thank you all!
Here is the solution for your problem:
SELECT stud.ExtId,
stud.FirstName,
stud.LastName,
stud.CommonEmail,
stud.Designation,
stud.Mifare,
prnt.Mifare
FROM Students AS stud
INNER JOIN Students AS prnt
ON stud.CommonEmail = prnt.CommonEmail
AND stud.Designation = 'Student'
AND prnt.Designation = 'Parent'
You can also follow the link to the demo:
http://sqlfiddle.com/#!9/5b790b/1
Select s.*
p.mifare
from students s
left join students p on p.commonemail=s.commonemail and p.Designation='Parent'
Try using the following Sub query
Select *,
(Select Mifare from students b where b.Designation = 'Parent' and b.commonemail = a.commonemail) as ParentMifare
from students a
I am not sure you can try this way join both the tables with email select only the designation student only.
Select
st.extid,
st.first_name,
st.last_name,
st.commonemail,
st.designation,
st. mifare
pr.parentmifare
from students st inner join students pr on st.commonemail=pr.commonemail
where pr.designation='student' and st.designation='parent'

Filtering with given value AND on FK

I've searched but couldn't fully get a question. I also tried to execute multiple query's in my query builder of my database program but the outcome isn't what I expect. So this is my question.
Let's say I two tables, hour_entries and employees ;
hour_entries has a PK (obv.) in it, and employees has a PK and a FK (This Foreign Key refers to the PK of table 1).
Let's say the columns in the table hour_entries are HourType(Programming, Cleaning etc.), a description and TotalHours(5, 2, etc.). And the FK which is called EmployeeID.
In this other table(employees) you have just the regular information about an employee. Firstname, lastname etc..
When I execute a query like so
SELECT FirstName, LastName, JobType, Description FROM hour_entries
LEFT (OUTER) JOIN employees on employees.EmployeeID = hour_entries.EmployeeID WHERE UPPER(Description) LIKE UPPER('%Bla%') OR UPPER(HourType) LIKE UPPER('%Bla%') AND EmployeeID = 4;
This seems to give me information back which matches the check for the description and hourtype. But it also returns rows with a different EmployeeID.
I want information of the employee with the given EmployeeID. So if you would put this in an if-statement it would look like this.
if(EmployeeID == givenID && Description == "Bla" || HourType == "Bla")
If the description is not a match it can also look if the hourtype is still a match. If the employeeID is not a match I don't want it to return any row. But it still does.
You need to keep all Joining conditions in On clause. In Where clause they effectively convert Left Join into Inner Join. In this particular case it should be hour_entries.EmployeeID, not employees.EmployeeID in Where. Also you miss brackets around OR:
SELECT FirstName, LastName, JobType, Description
FROM hour_entries
LEFT (OUTER) JOIN employees
ON employees.EmployeeID = hour_entries.EmployeeID
WHERE hour_entries.EmployeeID = 4 --<- "FROM" table here, not "JOIN"
AND ( --<- Brackets around OR
UPPER(Description) LIKE UPPER('%Bla%')
OR UPPER(HourType) LIKE UPPER('%Bla%')
); --<- Brackets around OR

At most one record can be returned by this subquery. (Error 3354)

Hi my query getting this error help me to recover it
SELECT CompanyId, CompanyName, RegistrationNumber,
(select CompanyAddress from RPT_Company_Address where
RPT_Company_Address.CompanyId=Company.CompanyId) AS CompanyAddress,
MobileNumber, FaxNumber, CompanyEmail, CompanyWebsite, VatTinNumber
FROM Company;`
Your subquery below is returning more than one result
select CompanyAddress
from RPT_Company_Address
where RPT_Company_Address.CompanyId = Company.CompanyId
Therefore more than one address matches your company id.
Try fixing the data or using:
select top 1 CompanyAddress
from RPT_Company_Address
where RPT_Company_Address.CompanyId = Company.CompanyId
It appears that your RPT_Company_Address table has more than one address for a given company. If this should not be possible, you should try to correct the data and modify your schema to prevent the possibility of this happening.
On the other hand, if there can be multiple addresses, you must decide how your query should handle them:
1) Do you want the same company row listed multiple times-- one per each address? If so, use an INNER JOIN to return them all:
SELECT Company.CompanyId, CompanyName, RegistrationNumber, CompanyAddress, ...
FROM Company
INNER JOIN RPT_Company_Address RCA ON RCA.CompanyId = Company.CompanyId
2) If you want only the first matching address, do a subquery on the first matching address corresponding to each company:
SELECT Company.CompanyId, CompanyName, RegistrationNumber, CompanyAddress, ...
FROM Company
INNER JOIN
(
SELECT CompanyId, ROW_NUMBER() OVER (ORDER BY 1 PARTITION BY CompanyId) AS Num
FROM RPT_Company_Address
) Addresses
ON Addresses.ComapnyId = Company.CompanyId
WHERE Num = 1
3) If you have some other way to identify the "primary" address that you want, include a WHERE clause with that criteria:
SELECT Company.CompanyId, CompanyName, RegistrationNumber, CompanyAddress, ...
FROM Company
INNER JOIN RPT_Company_Address RCA ON RCA.CompanyId = Company.CompanyId
WHERE RCA.PrimaryAddress = 1
Looks to me like your RPT_Company_Address table holds multiple entries for some CompanyIds.
I found this question because I was also getting this error, "At most one record can be returned by this subquery." My answer will not apply to the stated question, but I'm providing it in case the solution I found will help others or myself in the future troubleshoot that error.
All three of the answers given in 2014 say that the error indicates that the table RPT_Company_Address contains more than one record with the same value of the field CompanyId. However, in my case the field in the role of CompanyId is set as an index with no duplicates, so it cannot possibly have the same value in more than one record.
To explain my situation and the solution I found, I will first reduce the questioner's code to the minimum relevant content by removing irrelevant fields:
SELECT
(select CompanyAddress from RPT_Company_Address
where RPT_Company_Address.CompanyId = Company.CompanyId) AS CompanyAddress
FROM Company;
However, in my case, I did not initially prefix the second occurrence of CompanyId with the table name Company. Thus my initial code was like:
SELECT
(select CompanyAddress from RPT_Company_Address
where RPT_Company_Address.CompanyId = CompanyId) AS CompanyAddress
FROM Company;
And that apparently was the cause of the error. When I inserted the prefix Company. on the second occurrence of CompanyId, the error went away.
I don't know why the code without that second prefix made the subquery behave as if it was returning multiple values, or made Access think it was behaving that way, but inserting that prefix corrected the behavior.