1

I am new and still learning so please excuse my codes. I have googled and as last resort posting for help. Hope one of the senior programmers can help.

What I am trying to achieve: which course has below average number of students?

I am using SQL Server Management Studio v18.

My code does not work and I can not understand why derived table is not being accepted. I am aware that I can create another subquery and achieve it but still want to understand why derived table C in this case is not working?

Please help with explanation and suggest simplest way to achieve this query.

select 
    c.course, c.num_of_students
from
    (select 
         course, count(pname) as num_of_students
     from 
         Studies
     group by 
         COURSE) c
where 
    c.num_of_students < (select avg(c.num_of_students) from c);

I get this error:

Invalid object name 'c'

This invalid object name is highlighted in the WHERE clause line.

Data displays properly in the preview.

Data:

PNAME INSTITUTE COURSE COURSEFEE
ANAND SABHARI PGDCA 4500
ALTAF COIT DCA 7200
JULIANA BDPS MCA 22000
KAMALA PRAGATHI DCA 5000
MARY SABHARI PGDCA 4500
NELSON PRAGATHI DAP 6200
PATRICK PRAGATHI DCAP 5200
QADIR APPLE HDCA 14000
RAMESH SABHARI PGDCA 4500
REBECCA BRILLIANT DCAP 11000
REMITHA BDPS DCS 6000
REVATHI SABHARI DAP 5000
VIJAYA BDPS DCA 48000
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 5
    If you need to reference a derived table twice use a CTE instead. The derived table definition needs to be repeated after every `from` that uses that definition (and you would need to give it a new alias on the second occasion too) – Martin Smith Jan 06 '22 at 13:37
  • If this query is going to be a one and done thing then squillman's answer is the most effective way of doing it; but if the average is going to be used further down in the script, then it's worth looking at variables and temporary tables. – Andrew Corrigan Jan 06 '22 at 13:54

1 Answers1

3

Derived tables have limited scope within a query and can only be referenced once after FROM. You have a few options, the best of which is a CTE:

WITH c AS (
    SELECT
        course, COUNT(pname) as num_of_students
    FROM Studies
    GROUP BY course
)
SELECT
    c.course, c.num_of_students
FROM c
WHERE
    c.num_of_students < (SELECT AVG(c.num_of_students) FROM c);

Additional options, although probably less desirable in this situation unless you need to use the results in your derived table in other queries, would be to define a temp table or a table variable:

Temp table:

DROP TABLE IF EXISTS #c;
SELECT
    course, COUNT(pname) as num_of_students
INTO #c
FROM Studies
GROUP BY course;

SELECT
    c.course, c.num_of_students
FROM #c c
WHERE
    c.num_of_students < (SELECT AVG(c.num_of_students) FROM c);

DROP TABLE #c;

Table variable:

DECLARE @c TABLE (
    course VARCHAR(100),
    num_of_students INT
);

INSERT @c (course, num_of_students)
SELECT course, COUNT(pname)
FROM Studies
GROUP BY course;

SELECT
    c.course, c.num_of_students
FROM @c c
WHERE
    c.num_of_students < (SELECT AVG(c.num_of_students) FROM c);
squillman
  • 13,363
  • 3
  • 41
  • 60