pass results of one query into another in SQL - sql

I have two queries:
SELECT g.id FROM "group" g INNER JOIN group_role gr on g.id = gr.group_fk
INNER JOIN role_details rd on rd.group_role_fk = gr.id
INNER JOIN mandate m on m.role_details_fk = rd.id where m.id = x
and
SELECT p.id, p.name, g.name, g.id
FROM person p INNER JOIN position pos on p.id = pos.person_fk
INNER JOIN role_details rd on rd.id = pos.role_details_fk
INNER JOIN group_role gr on gr.id = rd.group_role_fk
INNER JOIN "group" g on g.id = gr.group_fk
WHERE g.id = y
I would like to be able to pass g.id into the second query so that for a given "x", I get p.id, p.name, g.name, g.id returned. How can I do this? Can it be done with more joins?

You can nest your queries like this, called Sub Queries, assumed both queries are working and the subquery only returns a single value.
SELECT p.id, p.name, g.name, g.id
FROM person p INNER JOIN position pos on p.id = pos.person_fk
INNER JOIN role_details rd on rd.id = pos.role_details_fk
INNER JOIN group_role gr on gr.id = rd.group_role_fk
INNER JOIN "group" g on g.id = gr.group_fk
WHERE g.id = (SELECT g.id FROM "group" g INNER JOIN group_role gr on g.id = gr.group_fk
INNER JOIN role_details rd on rd.group_role_fk = gr.id
INNER JOIN mandate m on m.role_details_fk = rd.id where m.id = x)

The easiest way would be to use a subquery like
SELECT p.id, p.name, g.name, g.id
FROM person p INNER JOIN position pos on p.id = pos.person_fk
INNER JOIN role_details rd on rd.id = pos.role_details_fk
INNER JOIN group_role gr on gr.id = rd.group_role_fk
INNER JOIN "group" g on g.id = gr.group_fk
WHERE g.id IN (SELECT g2.id FROM "group" g2 INNER JOIN group_role gr on g2.id = gr.group_fk
INNER JOIN role_details rd on rd.group_role_fk = gr.id
INNER JOIN mandate m on m.role_details_fk = rd.id where m.id = x)
Take care to use different aliases in the subquery unless you want to address the exact row you are looking at in the outer query.
To avoid the subquery you can reformulate the query using more joins - possibly joining the same table more than once using different aliases. Depending on the DBMS this might gain you some performance.

Related

Re-writing query from in() to joins

Can you assist in re-writing this into joins?
select * from users where users.advised_by in (
select p.id
from advisors p
join advisor_members m on p.id = m.advisor_id
join representatives r on m.user_id=r.user_id
where m.memeber_type='Advisor'
)
This is part of 200+ row query and that in() statement is hard to maintain when there are changes.
you should use a proper on clause
select *
from users
inner join
(
select p.id
from advisors p
join advisor_members m on p.id = m.advisor_id
join representatives r on m.user_id=r.user_id
where m.memeber_type='Advisor'
) t on users.advised_by = t.id
/*Option 1 */
SELECT *
FROM users usr
INNER JOIN
(
SELECT p.id AS advisor_id
FROM advisors p
JOIN advisor_members m
ON p.id = m.advisor_id
JOIN representatives r
ON m.user_id=r.user_id
WHERE m.memeber_type='Advisor' ) T2 usr.advised_by = t2.advisor_id
/*Option2 -- */
SELECT *
FROM users usr
INNER JOIN advisors p
ON usr.advised_by=p.id
JOIN
(
SELECT *
FROM advisor_members
WHERE m.memeber_type='Advisor') m
ON p.id = m.advisor_id
JOIN representatives r
ON m.user_id=r.user_id

Selecting single column multiple times based on different conditions

I have written a SQL query to retrieve required data and it looks like given below:
SELECT distinct p.person_id,p.birth_date,p.gender_code,
wm_concat(distinct r.race_code) as race_code,p.hispanic_latino_code,
c.clinically_diagnosed_code,
wm_concat(distinct c.characteristic_code) as chara_codes,
p.prev_adopted_code,p.age_adopted,
FIRST_VALUE(pe.removed_date) OVER (ORDER BY pe.removed_date),
count(pe.removed_date) as removal_count,
LAST_VALUE(pe.discharge_date) OVER (ORDER BY pe.discharge_date),
LAST_VALUE(pe.removed_date) OVER (ORDER BY pe.removed_date) as latest_removal_date,pe.created_date,
pe.removal_circumstance_code,wm_concat(distinct rr.removal_reason_code) as removal_reasons,
ps.placement_type_code,ps.icpc_placement_flag,pe.caretaker_structure_code
FROM PERSON p left outer join RACE r on p.person_id = r.person_id
left outer join CHARACTERISTIC c on c.person_id = p.person_id
left outer join PLACEMENT_EPISODE pe on p.person_id = pe.child_id
left outer join PLACEMENT_SETTING ps on p.person_id = ps.child_id
left outer join REMOVAL_REASON rr on pe.placement_episode_id = rr.placement_episode_id
GROUP BY p.person_id,p.birth_date,p.gender_code,p.hispanic_latino_code,
c.clinically_diagnosed_code,p.prev_adopted_code,p.age_adopted,pe.removed_date,
pe.discharge_date,pe.removed_date,pe.created_date,pe.removal_circumstance_code,
ps.placement_type_code,ps.icpc_placement_flag,pe.caretaker_structure_code
ORDER BY p.person_id
In the above mentioned query, I have already selected birth date for a person. Now again in select clause I want to select birth_date for persons with following condition:
condition 1: p.person_id = pe.primary_caretaker_id
condition 2: p.person_id = pe.secondary_caretaker_id
Can someone tell me the way to select these fields(birth_date based on two different conditions) in the existing query?
Birth_date has been already selected once for individual person. Now I want to retrieve birth_date for primary_caretaker and secondary_caretaker.
You will need to join to the PERSON table twice more:
SELECT distinct p.person_id,p.birth_date,p.gender_code,
wm_concat(distinct r.race_code) as race_code,p.hispanic_latino_code,
c.clinically_diagnosed_code,
wm_concat(distinct c.characteristic_code) as chara_codes,
p.prev_adopted_code,p.age_adopted,
FIRST_VALUE(pe.removed_date) OVER (ORDER BY pe.removed_date),
count(pe.removed_date) as removal_count,
LAST_VALUE(pe.discharge_date) OVER (ORDER BY pe.discharge_date),
LAST_VALUE(pe.removed_date) OVER (ORDER BY pe.removed_date) as latest_removal_date,
pe.created_date,
pe.removal_circumstance_code,wm_concat(distinct rr.removal_reason_code) as removal_reasons,
ps.placement_type_code,ps.icpc_placement_flag,pe.caretaker_structure_code,
primCare.birth_date as primary_carer_birth_date,
secCare.birth_date as secondary_carer_birth_date,
FROM PERSON p left outer join RACE r on p.person_id = r.person_id
left outer join PERSON primCare on primCare.person_id = pe.primary_caretaker_id
left outer join PERSON secCare on secCare.person_id = pe.secondary_caretaker_id
left outer join CHARACTERISTIC c on c.person_id = p.person_id
left outer join PLACEMENT_EPISODE pe on p.person_id = pe.child_id
left outer join PLACEMENT_SETTING ps on p.person_id = ps.child_id
left outer join REMOVAL_REASON rr on pe.placement_episode_id = rr.placement_episode_id
GROUP BY p.person_id,p.birth_date,p.gender_code,p.hispanic_latino_code,
c.clinically_diagnosed_code,p.prev_adopted_code,p.age_adopted,pe.removed_date,
pe.discharge_date,pe.removed_date,pe.created_date,pe.removal_circumstance_code,
ps.placement_type_code,ps.icpc_placement_flag,pe.caretaker_structure_code, primCare.birth_date, secCare.birth_date
ORDER BY p.person_id

AVG of AVG, aggregate functions of subquery

This subquery produces the correct table. But now I want to get the average of the averages, and I'm getting an error "Missing FROM-clause entry for table "c"".
SELECT
c.name,
AVG(avgvalue)
FROM
(
SELECT
c.name,
p.name,
AVG(a."value") AS avgvalue
FROM answers a INNER JOIN survey_responses sr ON sr.id = a.survey_response_id AND a.question_id = 13
INNER JOIN answers category_answer ON category_answer.survey_response_id = sr.id AND category_answer.question_id = 264
INNER JOIN answers_categories ac ON category_answer.id = ac.answer_id
INNER JOIN categories c ON c.id = ac.category_id
INNER JOIN products p ON p.id = a.product_id
WHERE c.name IN ('Accounting')
GROUP BY c.name, p."name"
HAVING count(p.name)>10
) as ProductAverages
GROUP BY c.name;
You are naming the ProductAverages, so your table aliases should reference it, not c - which can be used only in the inner query:
SELECT
name, -- Here
AVG(avgvalue)
FROM
(
SELECT
c.name,
p.name,
AVG(a."value") AS avgvalue
FROM answers a INNER JOIN survey_responses sr ON sr.id = a.survey_response_id AND a.question_id = 13
INNER JOIN answers category_answer ON category_answer.survey_response_id = sr.id AND category_answer.question_id = 264
INNER JOIN answers_categories ac ON category_answer.id = ac.answer_id
INNER JOIN categories c ON c.id = ac.category_id
INNER JOIN products p ON p.id = a.product_id
WHERE c.name IN ('Accounting')
GROUP BY c.name, p."name"
HAVING count(p.name)>10
) as ProductAverages
GROUP BY name; -- and here

wm_concat returning multiple of the same for select statment

I have this select statement:
select m.title, m.category_code, c.company_name, wm_concat(d.director_name),
wm_concat(a.actor_name) as actors
from
actors a
inner join actor_in_movies aim
on aim.actor_id = a.actor_id
inner join movies m
on m.movie_id = aim.movie_id
inner join movie_directors md
on md.movie_id = m.movie_id
inner join directors d
on d.director_id = md.director_id
inner join companies c
on c.company_id = d.company_id
group by m.title, m.category_code, c.company_name;
and it returns the same directors name one time for every actor....any way around this happening?
Tried this too:
select m.title, cat.description, c.company_name, wm_concat(d.director_name),
wm_concat(a.actor_name) as actors
from
movie_categories cat
inner join movies m
on m.category_code = cat.category_code
inner join movie_directors md
on md.movie_id = m.movie_id
inner join directors d
on d.director_id = md.director_id
inner join companies c
on c.company_id = d.company_id
inner join actor_in_movies aim
on aim.movie_id = m.movie_id
inner join actors a
on a.actor_id = aim.actor_id
group by m.title, cat.description, c.company_name;
with the same results
EDIT:
Guess I just needed to think more, used distinct and got it!
select m.title, cat.description, c.company_name, wm_concat(distinct
d.director_name),
wm_concat(a.actor_name) as actors
from
movie_categories cat
inner join movies m
on m.category_code = cat.category_code
inner join movie_directors md
on md.movie_id = m.movie_id
inner join directors d
on d.director_id = md.director_id
inner join companies c
on c.company_id = d.company_id
inner join actor_in_movies aim
on aim.movie_id = m.movie_id
inner join actors a
on a.actor_id = aim.actor_id
group by m.title, cat.description, c.company_name;

Trouble with Full Text Search query

I'm having trouble with this full text search query I'm trying to run. I need to do a full text search on two tables. If any of the terms are in either table I need to return the records from the first table.
select R.* from Request R
inner join Patients P on R.PatientID = P.PatientID
inner join containstable(Request,(*),#keywords)AS KEY_TBL
ON R.RequestID = KEY_TBL.[Key]
full outer join
(select R.* from Request R
inner join Patients P on R.PatientID = P.PatientID
inner join containstable(Patients,(*),#keywords) AS KEY_TBL2
ON P.PatientID = KEY_TBL2.[Key]) as b on R.RequestID = b.RequestID
All I needed was a Union instead of a full outer join.
select R.* from Request R
inner join Patients P on R.PatientID = P.PatientID
inner join containstable(Request,(*),#keywords)AS KEY_TBL
ON R.RequestID = KEY_TBL.[Key]
UNION
select R.* from Request R
inner join Patients P on R.PatientID = P.PatientID
inner join containstable(Patients,(*),#keywords) AS KEY_TBL2
ON P.PatientID = KEY_TBL2.[Key]