SQL join query - selecting from two tables - sql

I have a query which checks a table for a number of fields. The two tables I am interested in are: PERSON & PERSON_ALTERNATE_ID.
I want to modify my query to also return the value stored in person_alternate_id (if the particular person indeed has one)
select distinct person.person_id, person_name, person_address
from person join person_alternate_id
on
person.person_id=person_alternate_id.person_id
where person.person_id
in (10001,10002,10003);
Can anyone suggest how I could do that? I was looking at nested select examples, but I wasn't able to implement a suitable change to my query that achieved what I require. At the moment, the query only returns fields I need from the PERSON table.

Because the person may or may not have an alternate id, you should use a left join:
select person.person_id, person_name, person_address, person_alternate_id.*
from person
left join person_alternate_id
on person.person_id=person_alternate_id.person_id
where person.person_id
in (10001,10002,10003);

Related

Selecting a grouping that matches a certain criteria, SQL

I have two relations, one is a list of the areas an instructor is able to teach (AreasOfInstructor(InstructorNo,AreaName)) and the other is the result of a subquery that returns a list of AreaNames. I want to group the AreaOfInstructor relation by InstructorNo, and then return each instructor (as represented by InstructorNo) that is able to teach all the areas returned by the subquery.
My attempt:
SELECT InstructorNo
FROM AreasofInstructor
GROUP BY InstructorNo
/**WHERE THE GROUP CONTAINS* (the list of AreaNames returned by the subquery)*/
I'm not sure what the actual SQL commands are that will implement the stuff between the stars on the last line. Thanks for the help!
Edit: Just to be clear, what I'm looking for is the set of instructors that are able to teach in the areas that are returned by the subquery.
To do this, you can join both relations, group by InstructorNo, and then validate that the distinct count of AreaNames per InstructorNo matches the distinct count of AreaNames in the AreaNames relation.
with AreaNames as (subquery)
select i.InstructorNo, count(distinct i.AreaName)
from AreasofInstructor i
join AreaNames n
on n.AreaName = i.AreaName
group by i.InstructorNo
having count(distinct i.AreaName) = (select count(distinct AreaName) from AreaNames)
It's better to use Common Table Expression are more readable than a sub-query.
Check if this is what you are looking for?
WITH Areas (AreaName)
AS
(
*sub-query goes here*
)
SELECT DISTINCT
InstructorNo
FROM
AreasOfInstructor AOI
INNER JOIN
Areas A ON AOI.AreaName = A.AreaName

Ms-Access: counting from 2 tables

I have two tables in a Database
and
I need to retrieve the number of staff per manager in the following format
I've been trying to adapt an answer to another question
SELECT bankNo AS "Bank Number",
COUNT (*) AS "Total Branches"
FROM BankBranch
GROUP BY bankNo
As
SELECT COUNT (*) AS StaffCount ,
Employee.Name AS Name
FROM Employee, Stafflink
GROUP BY Name
As I look at the Group BY I'm thinking I should be grouping by The ManID in the Stafflink Table.
My output with this query looks like this
So it is counting correctly but as you can see it's far off the output I need to get.
Any advice would be appreciated.
You need to join the Employee and Stafflink tables. It appears that your FROM clause should look like this:
FROM Employee INNER JOIN StaffLink ON Employee.ID = StaffLink.ManID
You have to join the Eployee table twice to get the summary of employees under manager
select count(*) as StaffCount,Manager.Name
from Employee join Stafflink on employee.Id = StaffLink.EmpId
join Employee as Manager on StaffLink.ManId = Manager.Id
Group by Manager.Name
The answers that advise you on how to join are correct, assuming that you want to learn how to use SQL in MS Access. But there is a way to accomplish the same thing using the ACCESS GUI for designing queries, and this involves a shorter learning curve than learning SQL.
The key to using the GUI when more than one table is involved is to realize that you have to define the relationships between tables in the relationship manager. Once you do that, designing the query you are after is a piece of cake, just point and click.
The tricky thing in your case is that there are two relationships between the two tables. One relationship links EmpId to ID and the other links ManId to ID.
If, however, you want to learn SQL, then this shortcut will be a digression.
If you don't specify a join between the tables, a so called Cartesian product will be built, i.e., each record from one table will be paired with every record from the other table. If you have 7 records in one table and 10 in the other you will get 70 pairs (i.e. rows) before grouping. This explains why you are getting a count of 7 per manager name.
Besides joining the tables, I would suggest you to group on the manager id instead of the manager name. The manager id is known to be unique per manager, but not the name. This then requires you to either group on the name in addition, because the name is in the select list or to apply an aggregate function on the name. Each additional grouping slows down the query; therefore I prefer the aggregate function.
SELECT
COUNT(*) AS StaffCount,
FIRST(Manager.Name) AS ManagerName
FROM
Stafflink
INNER JOIN Employee AS Manager
ON StaffLink.ManId = Manager.Id
GROUP BY
StaffLink.ManId
I don't know if it makes a performance difference, but I prefer to group on StaffLink.ManId than on Employee.Id, since StaffLink is the main table here and Employee is just used as lookup table in this query.

SQL WHERE <from another table>

Say you have these tables:
PHARMACY(**___id_pharmacy___**, name, addr, tel)
PHARMACIST(**___Insurance_number___**, name, surname, qualification, **id_pharmacy**)
SELLS(**___id_pharmacy___**, **___name___**, price)
DRUG(**___Name___**, chem_formula, **id_druggistshop**)
DRUGGISTSHOP(**___id_druggistshop___**, name, address)
I think this will be more specific.
So, I'm trying to construct an SQL statement, in which I will fetch the data from id_pharmacy and name FROM PHARMACY, the insurance_number, name, and surname columns from PHARMACIST, for all the pharmacies that sell the drug called Kronol.
And that's basically it. I know I'm missing the relationships in the code I wrote previously.
Note: Those column names which have underscores left and right to them are underlined(Primary keys).
The query you've written won't work in any DBMS that I know of.
You'll most likely want to use some combination of JOINs.
Since the exact schema isn't provided, consider this pseudo code, but hopefully it will get you on the right track.
SELECT PH.Ph_Number, PH.Name, PHCL.Ins_Number, PHCL.Name, PHCL.Surname
FROM PH
INNER JOIN PHCL ON PHCL.PH_Number = PH.Ph_Number
INNER JOIN MLIST ON MLIST.PH_Number = PH.PH_Number
WHERE MLIST.Name = "Andy"
I've obviously assumed some relationships between tables that may or may not exist, but hopefully this will be pretty close. The UNION operator won't work because you're selecting different columns and a different number of columns from the various tables. This is the wrong approach all together for what you're trying to do. It's also worth mentioning that a LEFT JOIN may or may not be a better option for you, depending on the exact requirements you're trying to meet.
Ok, try this query:
SELECT A.id_pharmacy, A.name AS PharmacyName, B.Insurance_number,
B.name AS PharmacistName, B.surname AS PharmacistSurname
FROM PHARMACY A
LEFT JOIN PHARMACIST B
ON A.id_pharmacy = B.id_pharmacy
WHERE A.id_pharmacy IN (SELECT id_pharmacy FROM SELLS WHERE name = 'Kronol')

MySQL 5.5 Database Query Help

I am having a few issues with a DB query.
I have two tables, students (Fields: FirstName, LastName, StdSSN), and teachers (TFirstName, TLastName, TSSN) which I've stripped down for this example. I need to perform a query that will return all the students except for the students that are teachers themselves.
I have the query
SELECT student.FirstName, student.LastName
FROM `student`,`teachers`
WHERE student.StdSSN=teachers.TSSN
Which gives me a list of all the teachers who are also students it does not provide me with a list of students who are not teachers, so I tried changing to:
SELECT student.FirstName, student.LastName
FROM `student`,`teachers`
WHERE student.StdSSN!=teachers.TSSN
Which gives me a list of all the students with many duplicate values so I am a little stuck here. How can I change things to return a list of all students who are not teachers? I was thinking INNER/OUTER/SELF-JOIN and was playing with that for a few hours but things became complicated and I did not accomplish anything so I've pretty much given up.
Can anyone give me any advice? I did see the query before and it was pretty simple, but I've failed somewhere.
Using NOT IN
SELECT s.*
FROM STUDENTS s
WHERE s.stdssn NOT IN (SELECT t.tssn
FROM TEACHERS t)
Using NOT EXISTS
SELECT s.*
FROM STUDENTS s
WHERE NOT EXISTS (SELECT NULL
FROM TEACHERS t
WHERE t.tssn = s.stdssn)
Using LEFT JOIN / IS NULL
SELECT s.*
FROM STUDENTS s
LEFT JOIN TEACHERS t ON t.tssn = s.stdssn
WHERE t.column IS NULL
I used "column" for any column in TEACHERS other than what is joined on.
Comparison:
If the column(s) compared are nullable (value can be NULL), NOT EXISTS is the best choice. Otherwise, LEFT JOIN/IS NULL is the best choice (for MySQL).

SQL need most efficient way to select items list with sublists?

Lets look at some very simple example, have 3 tables:
dbo.Person(PersonId, Name, Surname)
dbo.Pet(PetId, Name, Breed)
dbo.PersonPet(PersonPetId, PersonId, PetId)
Need to select all persons with theirs pets if person has any.... for ex. in final application it should look smth like:
whats the most efficient way:
Select all persons and then in data access layer fill each person pets list with separate select?
Use join in sql level and then in data access layer filter all persons duplicates, by adding only one to result list and from other just filling pet list?
any other ideas?
The most efficient way is to select them all at once:
select p.*, pt.*
from Person p
left outer join PersonPet pp on p.PersonId = pp.PersonId
left outer join Pet pt on pp.PetId = pt.PetId
Need to select all persons with theirs pets if person has any...
Use:
SELECT per.name,
per.surname,
pt.name
FROM dbo.PERSON per
LEFT JOIN dbo.PERSONPET perpet ON perpet.personid = per.personid
JOIN dbo.PETS pt ON pt.petid = perpet.petid
Personally I would do it as a stored proc on the sql server. Whichever way you do it though, for display purposes you're going to have to filter out the duplicate Name and Surname.
The majority of the time taken to retrieve records is spent setting up and tearing down a query to the database. It doesn't make much difference how much data or how many tables you use in the query. It will be much more efficient to use a single query to get all the data. If your data access layer fetches each separately you'll get poor speed. Definitely use a join.
If your client and back end support multiple result sets you could also do somthing like (assuming its MSSQL)
Create Proc usp_GetPeopleAndPets
AS
BEGIN
SELECT PersonId, Name, Surname
FROM
dbo.Person p;
SELECT
pp.PersonID,
p.PetId, p.Name, p.Breed
FROM
dbo.PersonPet pp
INNER JOIN dbo.Pet p
ON pp.PetId = p.PetId
Order BY pp.PersonId
END
The data retrieval time would be roughly equivalent since its one trip to the DB. Some clients support relationships between results which allow you to do something like
Person.GetPets() or Pet.GetPerson()
The main advantage to this approach is that if you're working with people you don't have to worry about the "filter[ing] all person duplicate[s]"