I have the following query that gets the papers grade listing.
SELECT DISTINCT papers.paper_id, papers.paper_title, AVG(paper_judge_participations.paper_judge_participation_score) AS final_grade,
(SELECT array_agg(paper_author_name) FROM paper_authors as authors WHERE authors.paper_id=papers.paper_id )::varchar as paper_author_name
FROM papers
FULL JOIN paper_categories ON paper_categories.paper_category_id=papers.paper_category_id
LEFT JOIN paper_judge_participations ON papers.paper_id = paper_judge_participations.paper_id
WHERE ((papers.paper_note IS NULL AND final_grade >= 7) OR (papers.paper_note IS NOT NULL AND papers.paper_note >= 7)) AND papers.paper_category_id = 1
GROUP BY papers.paper_id ORDER BY final_grade, papers.paper_note;
I want to see if the final_grade variable from the the averae result is more than 7 but I get the error:
ERROR: column "final_grade" does not exist
LINE 6: WHERE ((papers.paper_note IS NULL AND final_grade >= 7) OR (...
How can I use the average result on my WHERE condition?
The distinct is unnecessary in the SELECT. Also you need to move the logic to the HAVING clause:
SELECT p.paper_id, p.paper_title,
AVG(pjp.paper_judge_participation_score) AS final_grade,
(SELECT string_agg(paper_author_name)
FROM paper_authors pa
WHERE pa.paper_id = p.paper_id
) as paper_author_name
FROM papers p LEFT JOIN
paper_categories pc
ON pc.paper_category_id = p.paper_category_id LEFT JOIN
paper_judge_participations pjp
ON p.paper_id = pjp.paper_id
HAVING p.paper_category_id = 1
GROUP BY p.paper_id
HAVING (p.paper_note IS NULL AND final_grade >= 7) OR
(p.paper_note IS NOT NULL AND p.paper_note >= 7) AND
ORDER BY final_grade, p.paper_note;
Comments:
The FULL OUTER JOIN is being turned into a LEFT OUTER JOIN by the WHERE clause. So, you might as well be explicit.
Instead of doing array_agg() and converting the results to a string, how about just using string_agg()?
Table aliases make the query easier to write and read.
And of course, the conditions on the final grade have been moved to the HAVING clause. The condition on the group stays in the WHERE.
Personally, I find it strange that you are using a correlated subquery for one aggregation and explicit aggregation for the other. I suppose that is a matter of preference. Under the circumstance, you might consider using a correlated subquery for both.
Related
I'm new to SQL and I'm not certain why I am getting this error. I am trying to left join a sub-query to another query in sql developer.
This is the first query,
SELECT DISTINCT
tl.species,
ag.age
FROM
age_list ag,
tree_list tl
WHERE
ag.tree_id = tl.tree_id
And then the sub-query I would like to left join where the tree_id = tree_number is,
SELECT DISTINCT
sl.tree_spon,
sl.tree_number
FROM spon_list sl
WHERE
sl.tree_spon < 10
When trying to do this I've tried to use,
SELECT DISTINCT
tl.species,
ag.age,
q1.tree_spon
FROM
age_list ag,
tree_list tl
LEFT OUTER JOIN (SELECT DISTINCT
sl.tree_spon,
sl.tree_number
FROM spon_list sl
WHERE sl.tree_spon < 10) q1 on q1.tree_number = tree_list.tree_id
WHERE
ag.tree_id = tl.tree_id
Whatever I change in terms of the alias' for the columns and tables I always get the error, "ORA-00904: invalid identifier error", and that "tree_list.tree_id is invalid identifier", though separately the queries run fine.
Can anyone help, is it an issue with both queries joining on the tl.tree_id?
You can use the ANSI join syntax throughout (rather than mixing in legacy comma joins), joining on ag.tree_id = sl.tree_number (or tl.tree_id = sl.tree_number but they're both equal given the previous join) and putting the filter on sl.tree_spon < 10 into the ON clause as well:
SELECT DISTINCT
tl.species,
ag.age,
sl.tree_spon,
sl.tree_number
FROM age_list ag
INNER JOIN tree_list tl
ON (ag.tree_id = tl.tree_id)
LEFT OUTER JOIN spon_list sl
ON (ag.tree_id = sl.tree_number AND sl.tree_spon < 10)
Change tree_list.tree_id to tl.tree_id
I make related queries and the counting does not work correctly, when I connect 4 and join and add a condition, it does not count correctly, but without the 4th joina and the condition it works correctly. first option result = 2
SELECT
pxixolog_details.*,
directions.direction,
COUNT(directions.direction) procent
FROM
pxixolog_details
LEFT JOIN psixologs_direction ON pxixolog_details.id = psixologs_direction.psixolog_id
LEFT JOIN directions ON directions.id = psixologs_direction.direction_id
LEFT JOIN psixologs_weeks ON pxixolog_details.id = psixologs_weeks.psixolog_id
WHERE
directions.direction IN(
'Трудности в отношениях',
'Проблемы со сном',
'Нежелательная агрессия'
)
AND birthday BETWEEN '1956-04-29' AND '2021-04-29' AND psixologs_weeks.week = '4'
GROUP BY
pxixolog_details.id
and the second one doesn't work correctly. result = 4
SELECT
pxixolog_details.*,
directions.direction,
COUNT(directions.direction) procent
FROM
pxixolog_details
LEFT JOIN psixologs_direction ON pxixolog_details.id = psixologs_direction.psixolog_id
LEFT JOIN directions ON directions.id = psixologs_direction.direction_id
LEFT JOIN psixologs_weeks ON pxixolog_details.id = psixologs_weeks.psixolog_id
LEFT JOIN psixologs_times ON pxixolog_details.id = psixologs_times.psixolog_id
WHERE
directions.direction IN(
'Трудности в отношениях',
'Проблемы со сном',
'Нежелательная агрессия'
)
AND birthday BETWEEN '1956-04-29' AND '2021-04-29' AND psixologs_weeks.week = '4'
AND (psixologs_times.time = '09:00' OR psixologs_times.time = '10:00')
GROUP BY
pxixolog_details.id
what am I doing wrong?
You get double the amount of results when doing 4 JOINs because through the new (4th) JOIN you allow 2 records (9:00 and 10:00 o'clock) for each of the other joined records in the first 3 JOINs. That can lead to the observed result.
Check your data and make sure that your 4th JOIN condition yields a 1:1 record matching with the other data.
The last table has psixologs_times matches multiple rows for each psixolog_id.
You can easily see this using a query:
select psixolog_id, count(*)
from psixologs_times
group by psixolog_id
having count(*) > 1;
How you fix this problem depends on what you want to do. The simplest solution is to use count(distinct):
COUNT(DISTINCT directions.direction) as procent
However, this might just be hiding the problem. You might want to choose one row from the psixologs_times table. Or pre-aggregate it. Or do something else.
I Need help have written a query in PostgreSQL 9.2 as below I need to
Return rows indicating zero when there’s no results, currently its returning no records even after trying to use COALESCE.
With S as (select test.Name as Test,result.value as result,concat(person.first_name,' ', person.last_name) as "Name",
extract (Year from (select (age (patient.birth_date)))) as age
from clinlims.analysis
INNER JOIN clinlims.test on analysis.test_id=test.id
INNER JOIN clinlims.result on analysis.id = result.analysis_id
INNER JOIN clinlims.sample_item on sample_item.id = analysis.sampitem_id
INNER JOIN clinlims.sample_human on sample_human.samp_id = sample_item.samp_id
INNER JOIN clinlims.patient on patient.id = sample_human.patient_id
INNER JOIN clinlims.person on person.id = patient.person_id)
select Test , coalesce (count(*),0) as "Number Positive"
from S where result = 'value' and test = 'Haemoglobin'
group by Test
I have checked the solution here PostgreSQL - count data as zero if it is null (when where clause is used)
but it’s not working in my case since I don’t want to move my where condition in the S TABLE since I will be querying from it using different queries later on.
Is it possible ?
Consider summing the conditional of WHERE clause:
select Test,
sum((result = 'value' and test = 'Haemoglobin')::integer) as "Number Positive"
from S
group by Test
I'm having trouble grouping by name (CC.Nome) in this query, can you help me out?
Here is my code:
SELECT
Registadas.CodigoVisualizado As Codigo,
CC.Nome as Entidade,
CC.Documento AS Documento,
CC.DataDocumento as DataDocumento,
ISNULL(ROUND((SELECT SUM(CASE
WHEN tbCCEntidades.Natureza = 'R'
THEN tbCCEntidades.TotalMoedaReferencia
ELSE -tbCCEntidades.TotalMoedaReferencia
END)
FROM tbCCEntidades
WHERE CC.IDEntidade = Entidades.ID), 2), 0) AS Saldo,
CC.Natureza As Natureza
FROM
tbCCEntidades AS CC
INNER JOIN
tbEntidades Entidades ON Entidades.ID = CC.IDEntidade
INNER JOIN
tbEntidadesRegistadas Registadas ON Registadas.IDEntidade = Entidades.ID
What happens is that this query gives the rows mixed like this:
The real problem with your query is that you haven't correlated the sub-query properly:
ISNULL(ROUND((
SELECT SUM( CASE
WHEN tbCCEntidades.Natureza = 'R'
THEN tbCCEntidades.TotalMoedaReferencia
ELSE - tbCCEntidades.TotalMoedaReferencia
END)
FROM tbCCEntidades
Where CC.IDEntidade = Entidades.ID ), 2), 0) AS Saldo,
In this FROM clause you didn't give an alias to the table, so in the WHERE clause neither of the sides of the filter is filtering the subquery. Both CC and Entidades are in the outer query, so this subquery isn't being filtered at all: It's getting the SUM of all rows in the entire table, every time.
I can't be sure of the fix just from this broken code. I would guess instead of CC you need to alias the table in the subquery, and use that alias on the left side of the filter.
Since your sub-query just returns a SUM() it doesn't need a GROUP BY at all, and since it's in a subquery, the SUM() would not be improved by adding a GROUP BY to your main query.
you have to put group by right after where conditions
like
select CC.Name,SUM(something) from TableName where SomeCondition group by CC.Name
and yes you have to put everything on select that is not a aggregate function in group by i would suggest you to go ahead with CTE expression.then make a join on other fields you needed from table.
The query works, it returns the data I need, the thing that I don't know is where to put the "Group By" in order to order the result by CC.Nome :/
You only want to sort your result rows? That's not GROUP BY, but ORDER BY:
...
ORDER BY Entidade;
I have a result set that has a defined grouping (for a report). There is a possibility that the position is not assigned and therefore does not have a "Grid_Group". In this case I assign a value of 99. This is working correctly except the order by, the 99 is always first and it should be last (If I do desc it is at bottom). I've tried a cast on the select side as well as within the order by on the Grid_Group, but both have same results with 99 at the top. (Sql server 2008)
Here is the snippet, I remove all other unneeded columns.
SELECT s.SessionNumber,Position.PositionName,(Select CASE when dbo.Position.Grid_Group is null THEN 99 ELSE dbo.Position.Grid_Group END) as Grid_Group
FROM dbo.USession AS us Left Outer JOIN
dbo.Position ON us.PositionId = dbo.Position.PositionId FULL OUTER JOIN
dbo.Sessions AS s ON us.SessionId = s.SessionId
ORDER BY S.SessionNumber, dbo.Position.Grid_Group
Thoughts?
You need to apply the CASE on your order by as well (bear in mind this will ruin index utilization on the sort operation). Your ORDER BY is referencing the original table's column, not your alias result column. Something like this should do the trick:
SELECT
s.SessionNumber,Position.PositionName,
(CASE
WHEN dbo.Position.Grid_Group IS NULL THEN 99
ELSE dbo.Position.Grid_Group
END) AS Grid_Group
FROM dbo.USession AS us
LEFT OUTER JOIN dbo.Position ON us.PositionId = dbo.Position.PositionId
FULL OUTER JOIN dbo.Sessions AS s ON us.SessionId = s.SessionId
ORDER BY
S.SessionNumber,
(CASE
WHEN dbo.Position.Grid_Group IS NULL THEN 99
ELSE dbo.Position.Grid_Group
END)
I allowed myself to apply some minor formatting of your SQL.
An ORDER BY will in this case not see your calculated columns. To get the effect you're asking for, you'll have to ORDER BY the same expression (which kastermester's answer is demonstrating), or wrap the query in a common table expression and ORDER BY while selecting from that, something like;
WITH cte AS (
SELECT s.SessionNumber, p.PositionName, COALESCE(p.Grid_Group, 99) Grid_Group
FROM dbo.USession AS us
LEFT OUTER JOIN dbo.Position p ON us.PositionId = p.PositionId
FULL OUTER JOIN dbo.Sessions s ON us.SessionId = s.SessionId
)
SELECT * FROM cte ORDER BY SessionNumber, Grid_Group;