I have a bunch of subqueries that each return a bunch of records with two ID fields. I need to return a list of all ID pairs that exist in all subqueries. I was thinking I could do something like this:
SELECT Q1.V1, Q1.V2
FROM ( [SUBQUERY1] ) AS Q1
INNER JOIN ( [SUBQUERY2] ) AS Q2 ON Q2.V1 = Q1.V1 AND Q2.V2 = Q1.V2
INNER JOIN ( [SUBQUERY3] ) AS Q3 ON Q3.V1 = Q2.V1 AND Q3.V2 = Q2.V2
INNER JOIN ( [SUBQUERY4] ) AS Q4 ON Q4.V1 = Q3.V1 AND Q4.V2 = Q3.V2
Is there a better way?
Apparently the answer is to use INTERSECT:
[SUBQUERY1]
INTERSECT
[SUBQUERY2]
INTERSECT
[SUBQUERY3]
INTERSECT
[SUBQUERY4]
Nice!
Intersect is probably better but you can also use group by along with HAVING COUNT(*) > number_of_subqueries clause.
select V1, V2
from
(
(subquery_1)
union
(subquery_2)
union
(subquery_3)
)
group by v1, v2
having count(*) > 3
Related
I am writing a query to look through and get two seperate averages based on where conditions.
I tried two select statetments but ended up with lots of duplicates.
Now I have a union which works pretty well, although I have my two fields in alternating rows instead of seperate columns.
Can anyone suggest a fix, sorry for the dodgy code!
SELECT
tblSkillName.skillName,
tblTestScores.skillUID,
AVG(tblTestScores.percentage) AS `cohortPercentage`
FROM
(
(
(
tblTestScores
INNER JOIN tblUsers ON tblUsers.email = tblTestScores.email
)
INNER JOIN tblTestDetails ON tblTestScores.testDetailsID = tblTestDetails.testDetailsID
)
INNER JOIN tblSkillName ON tblSkillName.skillUID = tblTestScores.skillUID
)
WHERE
teacherGroup = '9JS2/Cp'
AND tblTestScores.testDetailsID = 1
GROUP BY
skillName
UNION ALL
SELECT
tblSkillName.skillName,
tblTestScores.skillUID,
AVG(tblTestScores.percentage) AS `groupPercentage`
FROM
(
(
(
tblTestScores
INNER JOIN tblUsers ON tblUsers.email = tblTestScores.email
)
INNER JOIN tblTestDetails ON tblTestScores.testDetailsID = tblTestDetails.testDetailsID
)
INNER JOIN tblSkillName ON tblSkillName.skillUID = tblTestScores.skillUID
)
WHERE
tblTestScores.testDetailsID = 1
GROUP BY
skillName
ORDER BY
skillUID ASC
I'm currently trying to find the percentage of certain amount of preregistered users in my postgres db, the operation would be (1185 * 100) / 3104 = 38.17. To do that I'm using two select statements to retrieve each count, but I've been unable to operate between them:
+ count +
- 1185 -
- 3104 -
This is what I have:
select
count(*)
from crm_user_preregistred
left join crm_player on crm_user_preregistred."document" = crm_player."document"
left join crm_user on crm_player.user_id = crm_user.id
where crm_user.email is not null
union all
select
count(*)
from crm_user_preregistred
Thanks in advance for any hint or help.
you can use some with clause to simplifie your selects, substitute the values with your count(*) selects, maybe some formating to the result, and a check for 0 on value2
with temp_value1 as (
select 1185 as value1 ),
temp_value2 as (
select 3104 as value2 )
select (select temp_value1.value1::float * 100 from temp_value1) /
(select temp_value2.value2::float from temp_value2)
result :
38.17654639175258
with your selects:
with temp_value1 as (
select
count(*) as value1
from crm_user_preregistred
left join crm_player on crm_user_preregistred."document" = crm_player."document"
left join crm_user on crm_player.user_id = crm_user.id
where crm_user.email is not null
),
temp_value2 as (
select
count(*) as value2
from crm_user_preregistred
)
select (select temp_value1.value1::float * 100 from temp_value1) / (select temp_value2.value2::float from temp_value2)
You can do this in one query:
select count(*) filter (where cu.email is not null) * 100.0 / max(cup.cnt)
from (select cup.*, count(*) over () as cnt
from crm_user_preregistred cup
) cup left join
crm_player cp
on cup."document" = cp."document" left join
crm_user cu
on cp.user_id = cu.id
where cu.email is not null;
I suspect that the query could be simplified further, but without knowing your data model, it is hard to make specific suggestions.
I have a Questions group table like follows:
ID, NAME, DESCRIPTION, VERSION_ID
Versions table columns are:
ID, NUMBER, VERSION_STATE
VERSION_STATE is an enumerated that can be 0, 1 or 2.
I need to select all questions group that its version has thevVERSION_STATE 0 or 1, but if there is a questions group with a VERSION_STATE = 0 I don't have to return the questions group with the VERSION_STATE = 1.
The simplest approach is:
SELECT distinct QG.id FROM healthsafety.hs_questions_group QG
LEFT OUTER JOIN (SELECT * FROM healthsafety.hs_version) VERSION
ON QG.VERSION_ID = VERSION.ID
WHERE
VERSION.VERSION_STATE=0
OR VERSION.VERSION_STATE=1
The problem is that this query returns all questions group with the VERSION_STATE 0 or 1. If I remove the or clause, and there are not questions groups with VERSION_STATE = 0, I need to return the questions groups with VERSION_STATE = 1.
I think that I need an if else or case statement but I am stucked. Any Idea?
Note that I have to implement this using criteria, so I need to use the simplest solution.
SELECT *
FROM (
SELECT OG.ID,OG.NAME,OG.DESCRIPTION,VERSION.ID,VERSION.NUMBER,VERSION.VERSION_STATE,ROW_NUMBER()OVER(PARTITION BY OG.ID ORDER BY VERSION.VERSION_STATE ASC) as INDICATOR
FROM healthsafety.hs_questions_group QG
LEFT OUTER JOIN
(SELECT * FROM healthsafety.hs_version) VERSION
ON QG.VERSION_ID = VERSION.ID
WHERE
VERSION.VERSION_STATE=0
OR VERSION.VERSION_STATE=1
) AS ABC
WHERE (ABC.VERSION_STATE = 0 and ABC.INDICATOR = 1)
OR (ABC.VERSION_STATE = 1 and ABC.INDICATOR = 1)
Using a common table expression and a union all where the second query uses not exists() to only return rows where version_state=1 when rows with version_state=0 do not exist.
;with cte as (
select qg.id, v.version_state
from healthsafety.hs_questions_group qg
inner join healthsafety.hs_version version v
on qg.version_id = v.id
where v.version_state in (0,1)
)
select id
from cte
where version_state = 0
union all
select qg.id
from cte
where version_state = 1
and not exists (
select 1
from cte
where version_state = 0
)
Does anyone know a way to simplify this WHERE expression?
WHERE (
(#UserSpecialtyID in
(
SELECT CharacteristicSpecialties_Id
FROM ModalityVariantSpecialty
WHERE ModalityVariants_Id = ModalityVariants.Id
)
)
OR
NOT EXISTS
(
SELECT CharacteristicSpecialties_Id
FROM ModalityVariantSpecialty
WHERE ModalityVariants_Id = ModalityVariants.Id
)
)
Something like this should probably work but Im not exactly clear on the relationships for your tables. I could probably give a better example if you could explain the relationships.
SELECT
*
FROM MadalityVariants mv
LEFT JOIN ModalityVariantSpecialty mvs on mvs.ModalityVariants_ID = mv.ID
WHERE
#UserSpecialtyID = mvs.CharacteristicSpecialties_ID
OR
mvs.CharacteristicSpecialties_ID is null
WHERE (
#UserSpecialtyID in
(
SELECT COALESCE(CharacteristicSpecialties_Id, A.A)
FROM (SELECT #UserSpecialtyID A) A LEFT JOIN ModalityVariantSpecialty
ON ModalityVariants_Id = ModalityVariants.Id
)
)
this works well if CharacteristicSpecialties_Id is a NON NULLABLE field.
I am assuming that this is a WHERE clause of a SELECT on the table ModalityVariants
Would this work (The SQL is not tested)?
SELECT *
FROM ModalityVariants
LEFT OUTER JOIN ModalityVariantSpeciality
ON ModalityVariants.Id = ModalityVariants_ID
WHERE CharacteristicSpecialities_Id = #UserSpecialityID or
CharacteristicSpecialities_Id is NULL
Here's my attempt:
WHERE #UserSpecialtyID = COALESCE
(
SELECT TOP 1 CharacteristicSpecialties_Id
FROM ModalityVariantSpecialty
WHERE ModalityVariants_Id = ModalityVariants.Id
ORDER BY
CASE WHEN CharacteristicSpecialties_Id = UserSpecialtyID THEN 1
ELSE 2 END ASC
), #UserSpecialtyID)
If both ModalityVariants_Id and UserSpecialtyID match, the subquery returns CharacteristicSpecialties_Id, and the where succeeds
If only ModalityVariants_Id matches, the subquery returns a different ID, and the where fails
If neither matches, the subquery returns NULL, the COALESCE returns #UserSpecialtyID, and the where succeeds
Probably clearest is a variety of John Hartsock's answer, with a subquery to ensure the left join doesn't add any rows.
select *
from ModalityVariants mv
left join
(
select distinct ModalityVariants_ID
, CharacteristicSpecialties_ID
from ModalityVariantSpecialty
) as mvs
on mvs.ModalityVariants_ID = mv.ID
where #UserSpecialtyID = mvs.CharacteristicSpecialties_ID
OR
mvs.CharacteristicSpecialties_ID is null
I'll vote for John's answer :)
Suppose I have this query
SELECT * FROM (
SELECT * FROM table_a
WHERE id > 10 )
AS a_results LEFT JOIN
(SELECT * from table_b
WHERE id IN
(SElECT id FROM a_results)
ON (a_results.id = b_results.id)
I would get the error "a_results is not a table". Anywhere I could use the re-use the results of the subquery?
Edit: It has been noted that this query doesn't make sense...it doesn't, yes. This is just to illustrate the question which I am asking; the 'real' query actually looks something like this:
SELECT SQL_CALC_FOUND_ROWS * FROM
( SELECT wp_pod_tbl_hotel . *
FROM wp_pod_tbl_hotel, wp_pod_rel, wp_pod
WHERE wp_pod_rel.field_id =12
AND wp_pod_rel.tbl_row_id =1
AND wp_pod.tbl_row_id = wp_pod_tbl_hotel.id
AND wp_pod_rel.pod_id = wp_pod.id
) as
found_hotel LEFT JOIN (
SELECT COUNT(*) as review_count, avg( (
location_rating + staff_performance_rating + condition_rating + room_comfort_rating + food_rating + value_rating
) /6 ) AS average_score, hotelid
FROM (
SELECT r. * , wp_pod_rel.tbl_row_id AS hotelid
FROM wp_pod_tbl_review r, wp_pod_rel, wp_pod
WHERE wp_pod_rel.field_id =11
AND wp_pod_rel.pod_id = wp_pod.id
AND r.id = wp_pod.tbl_row_id
AND wp_pod_rel.tbl_row_id
IN (
SELECT wp_pod_tbl_hotel .id
FROM wp_pod_tbl_hotel, wp_pod_rel, wp_pod
WHERE wp_pod_rel.field_id =12
AND wp_pod_rel.tbl_row_id =1
AND wp_pod.tbl_row_id = wp_pod_tbl_hotel.id
AND wp_pod_rel.pod_id = wp_pod.id
)
) AS hotel_reviews
GROUP BY hotel_reviews.hotelid
ORDER BY average_score DESC
AS sorted_hotel ON (id = sorted_hotel.hotelid)
As you can see, the sub-query which makes up the found_query table is repeated elsewhere downward as another sub-query, so I was hoping to re-use the results
You can not use a sub-query like this.
I'm not sure I understand your query, but wouldn't that be sufficient?
SELECT * FROM table_a a
LEFT JOIN table_b b ON ( b.id = a.id )
WHERE a.id > 10
It would return all rows from table_a where id > 10 and LEFT JOIN rows from table_b where id matches.