在SELECT中创建一个子查询,返回一行结果

时间:2013-04-17 13:46:14

标签: sql optimization

我们可以在SELECT中创建一个返回一行结果的子查询吗?

例如,我必须使用如下所示的查询:

SELECT columnA as aliasA, columnB as aliasB,
(SELECT columnC FROM table2
WHERE clause2) as aliasC,
(SELECT  columnD FROM table2
WHERE clause2) as  aliasD
FROM table1
WHERE clause1

我想改进它,因为它需要太多的时间来执行。 有没有办法创建如下的查询:

SELECT columnA as aliasA, columnB as aliasB,
(SELECT columnC, columnD FROM table2
WHERE clause2) as (aliasC, aliasD)
FROM table1
WHERE clause1

由于

注意: 更具体地说,我举个例子: 我需要在第一季度的每个月获得学生的最佳和最差结果。 如果我加入表格,我会为同一个学生提供多行(每个月一个)但我需要:

SELECT firstname, lastname, 
(SELECT MAX(value) FROM results WHERE results.student_id = student.id AND results.date
BETWEEN 'JAN-01' AND 'JAN-31') AS best_result_of_jan,
(SELECT MIN(value) FROM results WHERE results.student_id = student.id AND results.date
BETWEEN 'JAN-01' AND 'JAN-31') AS worst_result_of_jan,
 ..., 
(SELECT MIN(value) FROM results WHERE results.student_id = student.id 
AND results.date BETWEEN 'MAR-01' AND 'MAR-31') AS worst_result_of_mar 
FROM student 
WHERE student.has_maths = 1

3 个答案:

答案 0 :(得分:3)

修改

SELECT s.firstname, s.lastname,
       t.best_result_of_jan, t.worst_result_of_mar
FROM student s 
LEFT JOIN (
    (SELECT student_id,
            MAX(CASE WHEN results.date BETWEEN 'JAN-01' AND 'JAN-31'
                     THEN value ELSE NULL END) best_result_of_jan,
            MIN(CASE WHEN results.date BETWEEN 'MAR-01' AND 'MAR-31'
                     THEN value ELSE NULL END) worst_result_of_mar
     FROM results
     GROUP BY student_id
    ) t ON t.student_id = s.id
WHERE s.has_maths = 1

子查询将数据转换为每个学生所需的列。外部查询然后将这些列添加到student表列。


首先,如果子查询返回标量结果(即单行或无结果),则原始查询将起作用。这样可以安全地转换为LEFT JOIN表单,这也可以导致单行(没有笛卡尔积)或没有行(fizzed join)。

   SELECT a.columnA as aliasA, a.columnB as aliasB,
          b.columnC as aliasC, b.columnD as aliasD
     FROM table1 a
LEFT JOIN table2 b ON clause2
    WHERE clause1;

确保为第1和第2条中的列添加别名。

注意:此类查询的计划将导致table2处理一次并且columnC / D已解析。您的原始查询可能导致逐行执行子查询,并导致两次启动,因此缺乏性能。

答案 1 :(得分:2)

您想要加入,例如:

SELECT table1.columnA as aliasA, table1.columnB as aliasB, 
       table2.columnC as aliasC,
       table2.columnD as aliasD
FROM table1 left outer join
     table2
     on clause2
WHERE clause1

答案 2 :(得分:0)

在查询中,如果数据范围参数相同,那么您可以编写一个包含最小和最大字段值的select语句。在目前的情况下,除了其他解决方案,您可以尝试UNION ALL语句并组合两组查询。这可能比子查询方法更快。例如:

Select A.FirstName,
   A.LastName,
   Sum(A.Best_JAN) as BEST_JAN,
   sum(A.Worst_MAR) as WORST_MAR
From (

    Select student.FirstName,
            student.LastName,
            MAX(result.value) as Best_JAN,
            0 as Worst_MAR
      From Student, Results
     Where Student.Studentid = Results.studentid
       and results.date BETWEEN 'JAN-01' AND 'JAN-31'
     Group By student.FirstName, student.LastName

    Union ALL

    Select student.FirstName,
           student.LastName,
           0 as Best_JAN,
           MIN(result.value) as Worst_MAR
      From Student, Results
     Where Student.Studentid = Results.studentid
       And results.date BETWEEN 'MAR-01' AND 'MAR-31'
     Group By student.FirstName, student.LastName

  ) as A

  Group By A.FirstName, A.LastName