【问题标题】:Getting single records back from joined tables that may produce multiple records从可能产生多条记录的连接表中获取单条记录
【发布时间】:2010-10-11 03:25:08
【问题描述】:

我有一个学生表和一个招生表;一个学生可以有多个注册记录,这些记录可以是活动的,也可以是非活动的。

我想获得一个包含单个学生记录和一个关于该学生是否有活跃注册的指示器的选择。

我曾考虑在一个内联 UDF 中执行此操作,该 UDF 使用学生 ID 连接到注册表,但我想知道是否有更好的方法在单个 select 语句中执行此操作。

UDF 调用可能类似于:

Select Student_Name,Student_Email,isEnrolled(Student_ID) from Student

替代方案 - 使用一条 SQL 语句 - 是什么样的?

【问题讨论】:

    标签: sql select grouping user-defined-functions group-by


    【解决方案1】:
      select students.name, 
    decode(count(1), 0, "no enrollments", "has enrollments")
         from students, enrollments 
         where 
           students.id = enrollments.sutdent_id and 
           enrollments.is_active = 1 group by students.name
    

    当然,用您的数据库使用的函数(或 case 语句)替换 decode。

    【讨论】:

      【解决方案2】:

      为什么不加入辅助选择?与其他解决方案不同,这不是为返回的每一行触发子查询,而是一次为每个人收集注册数据。语法可能不太正确,但你应该明白了。

      SELECT
          s.student_name,
          s.student_email,
          IsNull( e.enrollment_count, 0 )
      FROM
          Students s
      LEFT OUTER JOIN (
              SELECT
                  student_id,
                  count(*) as enrollment_count
              FROM
                  enrollments
              WHERE
                  active = 1
              GROUP BY
                  student_id
          ) e
      ON s.student_id = e.student_id
      

      从注册中选择也可以作为一个函数重做,它返回一个表供您加入。

      CREATE FUNCTION getAllEnrollmentsGroupedByStudent()
      RETURNS @enrollments TABLE
      (
          student_id       int,
          enrollment_count int
      ) AS BEGIN
          INSERT INTO
              @enrollments
          (
              student_id,
              enrollment_count
          ) SELECT
              student_id,
              count(*) as enrollment_count
          FROM
              enrollments
          WHERE
              active = 1
          GROUP BY
              student_id
      
          RETURN
      END
      
      
      SELECT
          s.student_name,
          s.student_email,
          e.enrollment_count
      FROM
          Students s
      JOIN 
          dbo.getAllEnrollmentsGroupedByStudent() e
      ON  s.student_id = e.student_id
      

      编辑:
      Renze de Waal 纠正了我的错误 SQL!

      【讨论】:

      • 请注意,如果学生没有注册,则加入会将这些学生排除在外。左连接会有所帮助,但随后的enrollment_count 可以为空。
      【解决方案3】:

      尽量避免使用 udf 或子查询,它们是性能杀手。 banjolity 似乎有一个很好的解决方案,因为它使用派生表而不是 UDF 或子选择。

      【讨论】:

        【解决方案4】:
        select  Student_Name,
                Student_Email,
                (select count(*) 
                 from Enrollment e 
                 where e.student_id = s.student_id
                ) Number_Of_Enrollments 
         from Student e
        

        将获得注册人数,这应该会有所帮助。

        【讨论】:

        • 如果您有 1000 名学生,此语句就像运行 1001 次查询,因为它分别查询每个学生的入学人数。
        • 不,没那么糟糕。数据库可以优化,特别是如果 student_id 是入学索引的第一部分(我认为它会是)。子查询只需要对注册索引执行索引范围扫描(不需要表本身)。
        【解决方案5】:

        试试这样的:

        SELECT Student_Name, Student_Email, CAST((SELECT TOP 1 1 FROM Enrollments e WHERE e.student_id=s.student_id) as bit) as enrolled FROM Student s
        

        我认为你也可以在select中使用exists语句但不是肯定的

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多