SQL Relation between more than 2 tables - sql

Let's say I got a table of Clients (tblClients) and a table of quotes (tblQuotes).
To get all quotes from our existing client, I did the following:
SELECT q.quoteId, c.contact, q.job,
FROM tblQuotes AS q
INNER JOIN tblClients AS c ON q.user = c.user
For each quote, we got a date the quotes was created. That date is in tblDate. The only way I found for displaying that date is when I display my records, I do an other request like this:
SELECT Date
FROM tblDate
WHERE id = %1 => %1 is q.quoteId
Everything works fine, but I decided to add inputs that alternate the SQL request. For example, c.Contact can be "John"
WHERE c.Contact = 'John'
How about the Date? I can easily get q.quoteId, c.Contact and q.Job but I don't know how to make it work with Date too.
WHERE c.Contact = 'John' AND ...

Just add another join (use INNER JOIN assuming each quote has a date value):
SELECT
q.quoteId, c.contact, q.job, d.Date
FROM
tblQuotes AS q INNER JOIN
tblClients AS c ON q.user = c.user INNER JOIN
tblDate AS d on d.id = q.quoteId
You can then modify accordingly to specify any additional criteria using the WHERE clause:
SELECT
q.quoteId, c.contact, q.job, d.Date
FROM
tblQuotes AS q INNER JOIN
tblClients AS c ON q.user = c.user INNER JOIN
tblDate AS d on d.id = q.quoteId
WHERE
d.Contact = 'John'

Related

sql subquery join group by

I am trying to get a list of our users from our database along with the number of people from the same cohort as them - which in this case is defined as being from the same medical school at the same time.
medical_school_id is stored in the doctor_record table
graduation_dt is stored in the doctor_record table as well.
I have managed to write this query out using a subquery which does a select statement counting the number of others for each row but this takes forever. My logic is telling me that I ought to run a simple GROUP BY query once first and then somehow JOIN the medical_school_id on to that.
The group by query is as follows
select count(ca.id) , cdr.medical_school_id, cdr.graduation_dt
from account ca
LEFT JOIN doctor cd on ca.id = cd.account_id
LEFT JOIN doctor_record cdr on cd.gmc_number = cdr.gmc_number
GROUP BY cdr.medical_school_id, cdr.graduation_dt
The long select query is
select a.id, a.email , dr.medical_school_id,
(select count(ba.id) from account ba
LEFT JOIN doctor bd on ba.id = bd.account_id
LEFT JOIN doctor_record bdr on bd.gmc_number = bdr.gmc_number
WHERE bdr.medical_school_id = dr.medical_school_id AND bdr.graduation_dt = dr.graduation_dt) AS med_count,
from account a
LEFT JOIN doctor d on a.id = d.account_id
LEFT JOIN doctor_record dr on d.gmc_number = dr.gmc_number
If you could push me in the right direction that would be amazing
I think you just want window functions:
select a.id, a.email, dr.medical_school_id, dr.graduation_dt,
count(*) over (partition by dr.medical_school_id, dr.graduation_dt) as cohort_size
from account a left join
doctor d
on a.id = d.account_id left join
doctor_record dr
on d.gmc_number = dr.gmc_number;
Using your same code for group by:
SELECT * FROM (
(
SELECT acc.[id]
, acc.[email]
FROM
account acc
LEFT JOIN
doctor doc
ON
acc.id = doc.account_id
LEFT JOIN
doctor_record doc_rec
ON
doc.gmc_number = doc_rec.gmc_number
) label
LEFT JOIN
(
SELECT count(acco.id)
, doc_reco.medical_school_id
, doc_reco.graduation_dt
FROM
account acco
LEFT JOIN
doctor doct
ON
acco.id = doct.account_id
LEFT JOIN
doctor_record doc_reco
ON
doct.gmc_number = doc_reco.gmc_number
GROUP BY
doc_reco.medical_school_id,
doc_reco.graduation_dt
) count
ON
count.[medical_school_id]=label.[medical_school_id]
AND
count.[graduation_dt]=label.[graduation_date]
)
how about something like this?
select a.doctor_id
, count(*) - 1
from doctor_record a
left join doctor_record b on a.medical_school_id = b.medical_school_id
and a.graduation_dt = b.graduation_dt
group by a.doctor_id
Subtract 1 from the count so that you're not counting the doctor in the "other folks in same cohort" number
I'm defining "same cohort" as "same medical school & graduation date".
I'm unclear on what GMC number is and how it is related. Is it something to do with cohort?

How do I use a table name that's returned in a select statement, in a join?

*Note: This is not the same as the "possible duplicate". Here, the table name will be different for each record returned in the SELECT statement. So I can't just "set" a variable like set #tableName = 'whatever'.
Here's my SQL - take a look at my last inner join. e.Name from the table EmailSendDefintion is the name of the table I need to join to. So, this is kind of dynamic, I know, but how do I join to a table that is stored in a field in another table?
select top 5000
x.HL_ACCT_ID as 'HL_ACCT_ID',
x.SALE_CODE as 'SALE_CODE',
s.SubscriberKey as 'EmailAddress',
o.EventDate as 'Opened',
c.EventDate as 'Clicked',
b.EventDate as 'Bounced'
from c100._sent s with (nolock)
inner join c100._job j with (nolock) on s.jobid = j.jobid
inner join emailsenddefinition e with (nolock) on e.customerkey = j.emailsenddefinition
left join c100._open o with (nolock) on o.jobid = s.jobid and o.subscriberkey = s.subscriberkey
left join c100._click c with (nolock) on c.jobid = s.jobid and c.subscriberkey = s.subscriberkey
left join c100._bounce b with (nolock) on b.jobid = s.jobid and b.subscriberkey = s.subscriberkey
inner join c100.[e.name] x with (nolock) on x.EmailAddress = s.SubscriberKey
where e.clientid = 100
Perhaps you could just create a view that outputs the union of all the e.name tables? Then join to the view.
In order to keep this short, let's say you have just 2 different tables whose name could be in the e.name column, SubscriberEmail1 and SubscriberEmail2.
Then you could create a view like this:
CREATE VIEW SubscriberEmailUnion
AS
SELECT
'SubscriberEmail1' as TableName,
HL_ACCT_ID,
SALE_CODE,
EmailAddress
FROM SubscriberEmail1
UNION
SELECT
'SubscriberEmail2' as TableName,
HL_ACCT_ID,
SALE_CODE,
EmailAddress
FROM SubscriberEmail2
GO
Note that each part of the view is adding the name of it's underlying table as a column. You can then change your final join to:
inner join SubscriberEmailUnion x with (nolock) on (
x.EmailAddress = s.SubscriberKey
AND x.TableName = e.Name
)
I'm personally most familiar with MS Sql Server so my sample uses that syntax. Should be easy enough to change to work with a different server if necessary though.
For performance you can then use whatever feature your DB has, indexed views etc.
How many tables do you have? If not too many one option would be to left join all of them
left join c100.table1 x1 on x1.EmailAddress = s.SubscriberKey and [e.name] = 'table1'
left join c100.table2 x1 on x2.EmailAddress = s.SubscriberKey and [e.name] = 'table2'
etc...
and then in the select
coalesce(x1.HL_ACCT_ID, x2.HL_ACCT_ID, etc...) as 'HL_ACCT_ID',

Self join on joined table

My query looks like
Select m.cw_sport_match_id as MatchId,
m.season_id as SeasonId,
s.title as SeasonName,
c.title as ContestName
from dbo.cw_sport_match m
inner join dbo.cw_sport_season s
ON m.season_id = s.cw_sport_season_id
inner join dbo.cw_sport_contest c
ON m.contest_id = c.cw_sport_contest_id
Where s.date_start <= GETDATE() AND s.date_end >= GETDATE()
order by s.date_start
No i need the name parent of the sport_contest (if there is one, it can be null). So basically a self join but no on the same table as the query is for. All the examples that i find do the self join are not done on another table.
can any sql pro help me?
So how can i join the cw_sport_season itself with the season_parent_id and get the title of it?
If I'm understanding your question correctly, you want to outer join the cw_sport_season table to itself using the season_parent_id field. Maybe something on these lines:
Select m.cw_sport_match_id as MatchId,
m.season_id as SeasonId,
s.title as SeasonName,
parent.title as ParentSeasonName,
c.title as ContestName
from dbo.cw_sport_match m
inner join dbo.cw_sport_season s
ON m.season_id = s.cw_sport_season_id
inner join dbo.cw_sport_contest c
ON m.contest_id = c.cw_sport_contest_id
left join dbo.cw_sport_season parent
ON s.season_parent_id = parent.cw_sport_season_id
Where s.date_start <= GETDATE() AND s.date_end >= GETDATE()
order by s.date_start

INNER JOIN SQL QUERY

the next sql statement work fine. it shows both patient_id and serv_name, but i try to show patient_name instead of patient_id
SELECT C1.patient_id, S.serv_name
FROM
Checkup_Details C
INNER JOIN Services S ON (C.serv_id=S.serv_id),
Checkup C1
WHERE
C1.today = DATE() AND C1.check_id=C.check_id
ORDER BY C.check_id
so how am i suppose to do that by adding this sql statement
INNER JOIN Patient P ON (C1.patient_id=P.patient_id)
but i don't know how exactely.
Assuming the field patient_name is in Checkup_Details, you have to put
SELECT C1.patient_name ...
instead from
SELECT C1.patient_id ...
Simply add the INNER JOIN clause to get the columns of the table Patient and change C1.patient_id by P.patient_name.
SELECT P.patient_name, S.serv_name
FROM
Checkup_Details C
INNER JOIN Services S ON (C.serv_id=S.serv_id),
INNER JOIN Patient P ON (C1.patient_id=P.patient_id)
Checkup C1
WHERE
C1.today = DATE() AND C1.check_id=C.check_id
ORDER BY C.check_id
You should not mix implicit and explicit join syntax. A simple rule: never use commas in the from clause:
SELECT C1.patient_id, S.serv_name
FROM Checkup_Details C INNER JOIN
Services S
ON C.serv_id = S.serv_id INNER JOIN
Checkup C1
ON C1.check_id = C.check_id INNER JOIN
Patient P
ON C1.patient_id = P.patient_id
WHERE C1.today = DATE()
ORDER BY C.check_id;

Selecting records with "at least one" condition on 1:n foreign key relationship

I have three tables in a SQL Server database: Submission, Quote, and Company. The foreign key relationships are 1:n for Submission:Quote and Company:Quote, i.e. a quote belongs to one submission and to one company. I have a query that selects all quotes for those submissions that have at least one quote with a specified company:
SELECT *
FROM Submission S, Quote Q, Company C
WHERE Q.submissionId = S.submissionId AND
Q.companyId = C.companyId AND
EXISTS (
SELECT *
FROM Quote T
WHERE T.submissionId = S.submissionId AND
T.companyId = #companyId
)
ORDER BY S.legalName
Is there a more efficient and/or more concise way to accomplish what I'm doing here? I just can't shake the feeling that there should be.
SELECT *
FROM Submission S
INNER JOIN Quote Q ON Q.submissionId = S.submissionId
INNER JOIN Company C ON Q.companyId = C.companyId
WHERE Q.companyId = #companyId
ORDER BY S.legalName
Edit
SELECT *
FROM Submission S
INNER JOIN Quote Q ON Q.submissionId = S.submissionId
INNER JOIN Company C ON Q.companyId = C.companyId
WHERE EXISTS (SELECT 1
FROM Submission Sub
INNER JOIN Quote Qt ON Qt.submissionId = Sub.submissionId
WHERE Sub.submissionId = S.submissionId
AND Qt.companyId = #companyId)
ORDER BY S.legalName
Join a sub-select statement to get specific submissionid's.
SELECT *
FROM Submission S
INNER JOIN Quote Q
ON Q.submissionId = S.submissionId
INNER JOIN Company C
ON Q.companyId =C.companyId
INNER JOIN (SELECT DISTINCT qt.submissionId
FROM Quote qt
WHERE qt.companyId = #companyId) Q2
ON Q2.submissionId = S.submissionId
ORDER BY S.legalName