Get data from relational tables - sql

I have following tables in my db.
Calls:
ID Name
1 Call1
2 Call2
3 Call3
Notes:
ID Name
1 Note 1
2 Note 2
Person:
ID Name
1 Andrew
PersonCalls:
ID CallID PersonID
1 1 1
2 2 1
PersonNotes:
ID NoteID PersonID
1 1 1
1 2 1
Now I need to get data from these tables according to person id. I am able to get data from 2 tables, for example Notes and PersonNotes, but I am not able to get combined data from these tables. This should be the result.
Result:
PersonID Note Call
1 Note1 Call1
1 Note2 Call2
Please suggest
Thanks

Use Join (ie: Inner Join):
select distinct p.ID as PersonID, n.Name as Note, c.Name as Call from Person p
inner join PersonCalls pc on p.ID = pc.PersonID
inner join PersonNotes pn on p.ID = pn.PersonID
inner join Calls c on pc.CallID = c.ID
inner join Notes n on pn.NoteID = n.ID

Without getting too detailed you can use a left join on dbo.calls.ID, dbo.notes.id, dbo.person.id, etc if you are using MS SQL server. Otherwise are you sure you can't just write a report?

Related

SQL: Unable to find a join or union to produce the following table

A Pupil table with { ID, LastName}
a Subject Table with {ID, SubjectName}
and a Report Table with {ID, PupilID, SubjectID, Grade}
There is a one-to-many relationship between Pupil and Report Tables, and Subject and Report Tables.
I want to generate a table like this for say subjectID = 1
Pupil.ID Pupil.LastName SubjectID Grade
1 --------------Smith ---------- 1 ------------B
2 --------------Jones ---------- 1 ------------NULL
3 -------------Weston ----------1 ------------NULL
4 -------------Knightly ---------1 -----------A
The problem is that the Report table would contain just 2 entries for subject 1:
PupilID SubjectID Grade
----1------- 1 ----------- B
----4------- 1 ----------- A
Left joins don't seem to work since there are only 2 entries in the report table for subject 1
SAMPLE DATA
{Pupil Table}
ID LastName
1 ...Smith
2 ...Jones
3 ...Weston
4 ...Knightly
{Subject Table}
ID SubjectName
1 ....Maths
2 ....Physics
3 ....Chemistry
{Report Table}
ID PupilID SubjectID Grade
1 .......1 ..........1 ..........B
2 .......4 ..........1 ..........A
When I do a search on SubjectID = 1 I want the table:
Pupil.ID .......Pupil.LastName ........SubjectID ...........Grade
1 --------------Smith ---------- 1 ------------B
2 --------------Jones ---------- 1 ------------NULL
3 -------------Weston ----------1 ------------NULL
4 -------------Knightly ---------1 -----------A
Access doesn't do subqueries very easily, so everything gets crammed into the FROM clause with a series of wrapped parentheses. Based on your sample data and my fighting Access to stop being unnecessarily difficult, I came up with this:
SELECT ps.Pupil_ID, ps.LastName, ps.Subject_ID, r.Grade
FROM (SELECT * FROM (SELECT ID AS Pupil_ID, LastName FROM Pupil) p,
(SELECT DISTINCT ID AS Subject_ID FROM Subject)) ps
LEFT JOIN REPORT r ON r.PupilID = ps.Pupil_ID AND r.SubjectID = ps.Subject_ID
ORDER BY Pupil_ID, Subject_ID;
The subquery "ps" is a cartesian join of the Pupil and Subject table views that I specified. At this point, your query would look like this:
(LastName column not shown for clarity)
StudentID|SubjectID
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
Now, using that Cartesian join subquery (pupilstudent -> ps), I use a LEFT JOIN to assign the Report table to each unique student's ID and subject ID. Therefore, if a student did not take a particular class, there will be a NULL value in the final result.
I tested this in Access using your sample data and it works on my machine.
Also as a note, it is poor practice to have a field called just ID in each table (e.g. in the Pupil table, ID becomes PupilID). This makes it much easier to use, and it self documents.
Cross join pupil and subject tables and left join result to report table
What you need is a cross join:
SELECT Pupil.ID, Pupil.LastName, SubjectID, Grade FROM
Pupil, Subject LEFT JOIN Report ON Subject.ID=Report.SubjectID
WHERE Subject.ID=1
To combine every pupil with every (or with a particular) subject, use cross join; Then use left join to get the corresponding grades:
select *
from pupil p cross join (select * from subject where id = 1) s
left join report on subjectId = s.id and pupilId = p.id

SQL joining to the same column id

I have a simple SQL query I just get to work out right. I've put together a test database like this;
TABLE MAIN
id name groupone grouptwo
1 Fred 1 3
2 bob 2 1
TABLE DETAIL
id group groupname
1 1 onegrp
2 2 twogrp
4 3 threegrp
My Select query is;
SELECT name, groupone, grouptwo, groupname
FROM main
INNER JOIN detail
ON main.groupone = detail.group
WHERE main.id = 1
The result I get is;
id name groupone grouptwo groupname
1 fred 1 3 onegrp
How do I change this to instead of giving the result as 1 and 3.
I get ... fred onegrp, threegrp
I've tried a dozen things but can't get it to work, I sort of want a give me the groupname again option but not sure what the syntax is for that! :(
Thanks in advance for your time and help
I think this is what you are after. You need to join the detail table twice, on the two different keys.
SELECT
m.Name
,a.groupname as 'GroupOne'
,b.groupname as 'GroupTwo'
FROM
main m
INNER JOIN
detail a
on m.groupone = a.group
INNER JOIN
detail b
on m.grouptwo = b.group
WHERE
m.id = 1

Joining 3 Tables Using Newest Rows

I have 3 tables in my database: children, families, statuslog
Every time a child is checked in or out of the database, it is updated in the statuslog. I've done this a long time ago, but I can't seem to figure out how to do it anymore. I want to create a new view that joins all 3 tables, but I only want the newest entry from statuslog (by using the highest id).
For example, statuslog looks like this:
childID researcher status id
1 Dr. A out 1
1 Dr. A in 2
1 Dr. B out 3
1 Dr. B in 4
2 Dr. C out 5
2 Dr. C in 6
3 Dr. B out 7
3 Dr. B in 8
This is what I want to do:
SELECT *
FROM children, families, statuslog
WHERE children.familyID = families.familyID AND children.childID = statuslog.childID
Obviously, this will return the children+families tuples coupled with every single log entry, but I can't remember how to only combine it with the newest log entry.
Any help would be appreciated!
Aggregate query with max(id) retrieves last ID given a childID. This is then joined to statuslog to retrieve other columns.
SELECT *
FROM children
INNER JOIN families
ON children.familyID = families.familyID
INNER JOIN
(
SELECT childID, researcher, status
FROM statuslog
INNER JOIN
(
SELECT childID, max(ID) ID
FROM statuslog
GROUP BY childID
) lastSL
ON statuslog.childID = lastSL.childid
AND statuslog.ID = lastSL.ID
) sl
ON children.childID = sl.childID
This seems to be the typical greatest-n-per-group in which the higher id is interpreted as the newest. This query should do the trick:
select * from (
select s1.* from statusLog s1
left join statusLog s2
on s1.childId = s2.childId and s1.id < s2.id
where s2.id is null
) final
join children c on c.childId = final.childId
join families f on f.familyId = c.familyId
Correct any syntactical errors.

SQL query: need help on subquery

Question is as follows:
There are 2 related tables (am giving some sample values for making it simplified):
Circuit
--------
id name
1 a
2 b
3 c
Circuit_Dependent
-----------------
id depend_id
1 2
1 3
the tables are related and second table tells the relation with the circuit id's.
Situation is query needed for:
1) list the circuit name which has the circuit_dependency
output expected:
name dependent_name
a b
a c
2) list the circuit name and count(no of dependancies)
output expected:
name count
a 2
appreciate help.
First query could be:
SELECT c1.`name`, c2.`name`
FROM Circuit_Dependent cd INNER JOIN Circuit c1
ON cd.id = c1.id
INNER JOIN Circuit c2
ON cd.depend_id = c2.id
Second query could be this one:
SELECT c.`name`, COUNT(DISTINCT cd.depend_id) AS count
FROM circuit c INNER JOIN Circuit_Dependent cd
ON c.id = cd.id
GROUP BY c.id

SQL Join to only one record in one to many relationship

I have the following query:
SELECT c.[ClientID]
,u.[AccessId]
FROM [tblClient] c
INNER JOIN [tblUser] u ON u.[Id] = c.[UserId]
This tblUser has multiple ID's for each UserID row.
So it would look like this:
UserID AccessID
1 AD2F0A-965B78414-2B34906F2-0127AA5A
1 ID2F0A9-65B784-142B34906-F20127AA5A
1 UD2F0A9-65B78-4142B34906F-20127AA5A
2 TD2F0A9-65B784142-B34906F-20127AA5A
2 RD2F0A9-65B784142B3-4906-F20127AA5A
3 WD2F0A96-5B784142-B34906F201-27AA5A
3 ZD2F0A96-5B784-142B34-906F2-0127AA5A
3 CD2F0A965-B784142B3-4906F20-127AA5A
Is there a way to only get the top(or 1) AccessId for each UserID? It doesnt matter which AccessID i get, I just want 1 of them.
Thanks
SELECT c.[ClientID], MAX(u.[AccessId])
FROM [tblClient] c
INNER JOIN [tblUser] u
ON u.[Id] = c.[UserId]
GROUP BY c.[ClientID]