SQL查询,用于确定一个表是否包含的属性多于另一个表

时间:2012-03-18 19:57:22

标签: postgresql join group-by aggregate-functions

我在做家庭作业时遇到问题如下:

  

找到所有教授比学生更多的部门。

所涉及的表格如下:

            Table "university.prof"
  Column   |         Type          | Modifiers
-----------+-----------------------+-----------
 pnum      | character(9)          | not null
 lastname  | character varying(12) | not null
 firstname | character varying(12) |
 dept      | character(4)          |
 office    | character(6)          |
 rank      | character(1)          |
 date_emp  | date                  | not null
 salary    | numeric(8,2)          |
 manager   | character(9)          |
Indexes:
    "prof_pkey" PRIMARY KEY, btree (pnum)

      Table "university.student"
  Column   |     Type      | Modifiers
-----------+---------------+-----------
 snum      | character(9)  | not null
 lastname  | character(12) |
 firstname | character(12) |
 dept      | character(4)  |
 date_ent  | date          |
 cr_comp   | smallint      |
 gpa       | numeric(4,3)  |
 advisor   | character(9)  |
Indexes:
    "student_pkey" PRIMARY KEY, btree (snum)

这个问题基本上要求一个值列表,其中左表的行数多于右表的值。我该怎么做呢?此查询不起作用:

SET search_path TO university;

SELECT dept
FROM prof
GROUP BY dept
HAVING count(*) > (
    SELECT count(*)
    FROM student
    GROUP BY dept
);

导致以下错误:

ERROR:  more than one row returned by a subquery used as an expression

此代码也不起作用,导致没有返回任何行(正确的答案返回两行):

SET search_path TO university;

SELECT prof.dept
FROM prof, student
GROUP BY prof.dept
HAVING count(prof.*) > count(student.*);

我该怎么做?我不是在寻找完整的答案,而是提示如何构建查询。我在Windows 7上使用PostgreSQL 9.1.3。

修改:感谢您的帮助。正确答案如下:

SET search_path TO university;

SELECT prof.dept
FROM prof, student
WHERE prof.dept = student.dept
GROUP BY prof.dept
HAVING count(DISTINCT prof.*) > count(DISTINCT student.*);

编辑2:有一个更好的解决方案。我接受了包含此解决方案的答案。

3 个答案:

答案 0 :(得分:2)

  

找到所有教授比学生更多的部门。

考虑一下这个:

SELECT p.dept, p.prof_ct, s.stud_ct
FROM (
   SELECT dept, count(*) AS prof_ct
   FROM   university.prof
   GROUP  BY dept
   ) p
LEFT JOIN (
   SELECT dept, count(*) AS stud_ct
   FROM   university.student
   GROUP  BY dept
   ) s USING (dept)
WHERE p.prof_ct >= s.stud_ct OR s.stud_ct IS NULL
ORDER BY p.dept;

比现在的解决方案快得多,因为学生和教授在dept之前加入的数量较少(按数量级)加起来计算。

它还观察到某个部门没有学生的情况,您的解决方案目前缺少这种情况。您的交叉联接会消除没有学生(或教授)的所有部门。

答案 1 :(得分:0)

导致错误的第一个查询的一部分:

SELECT dept
FROM prof
GROUP BY dept
HAVING count(*) > (
    SELECT count(*) /* This subquery would yield rows equal to no of different  
    FROM student        Department to which students belong.
    GROUP BY dept       Thus you can't compare it with > symbol.*/      
);

相反,你必须遍历professor表(选择的)并且每位教授计算该部门的教授的数量,然后相应地找到属于同一部分的学生系上述教授。 像这样:

select t.prof from prof t where
(
select count(*) from prof where dept=t.dept
)
>
(
select count(*) from student where dept=t.dept
)

答案 2 :(得分:0)

替代解决方案使用视图:

CREATE OR REPLACE TEMPORARY VIEW p AS (
    SELECT dept, count(*) num
    FROM prof
    GROUP BY dept
);
CREATE OR REPLACE TEMPORARY VIEW s AS (
    SELECT dept, count(*) num
    FROM student
    GROUP BY dept
);
SELECT DISTINCT p.dept
FROM p, s
WHERE p.num > s.num;

此代码正确处理了某个部门没有教授或学生的情况。