First, let's deal with your particular problem. When you use a subquery, you have to pay attention to its context. There are two contexts: table and scalar. In table context, the subquery is expected to return a set of rows. In scalar context, it needs to return a single value (one row with one column). How do you know which is which? Table context would be indicated by the following constructs:
FROM (...)
JOIN (...)
WHERE ... IN(...)
And scalar context is more or less anywhere else. If you are comparing the result of the subquery to a single value, like a column in a where clause, or are using the result as a computed column in a SELECT field list, then the subquery is in scalar context.
In your particular query, you are comparing the result of a subquery to NULL. Since NULL is a single value, we are talking about scalar context. As such, the subquery needs to return a single result. Yours is not, and it's probably happening because there are multiple schools to which a person belongs. No matter. I think I can divine what you are intending to do. You want to only include Persons which belong to at least one school. You can write this more effectively like so:
WHERE EXISTS(SELECT * FROM School S WHERE P.stdNo = S.stdNo)
You can replace the *
with a column or an expression. It doesn't really matter, as EXISTS()
tests to see if any rows are returned and doesn't do anything with the particular results.
You have a bigger problem, though, which is that you are doing a cartesian product of the Person and Class tables. I assume you actually want to match people to classes in some way. Because it's so easy to accidentally do a cartesian join with the comma operator, I always use and recommend the explicit JOIN
operators. You'll get a syntax error if you say INNER JOIN
(or some other type) without specifying a join predicate. So you should have something like this instead:
FROM Person P
JOIN Class C
ON <condition>
Now, for your other question about independent vs. correlated subqueries. An independent subquery is the easy case. It's a subquery that does not reference any of the tables or columns used outside of it in the query. A correlated subquery makes reference to a table or column used outside of it. Your subquery is correlated because it references P.stdNo
, which is included in the query outside of the subquery. A correlated subquery must be logically executed for every row in the context that it's contained in. In your case, every row examined by the WHERE clause results in the logical execution of the subquery, using the data from that particular row (in this case, P.stdNo
). Independent subqueries need only be logically executed once for obvious reasons.