3

执行摘要:在 SQL ANSI-89 下编写的查询需要转移到使用 SQL ANSI-92 的数据库中。涉及到外部连接。


我一直在运行 ANSI-89 查询

如果需要,我可以给出表结构,但基本思想是我们有一个员工表、一个在线课程表和一个中间“员工课程学习”表,其中包含员工 ID、课程 ID 和我们用作通过/失败指标的评级列。

我们的键列表样式是主键总是'id',而外键总是' tablename _id'。

这是选择的 ANSI-89 (MySQL 4.1.14) 版本:

SELECT E.id,
   E.firstname, E.surname, E.suffix,
   sum( if( ECT.rating =1, 1, 0 ) ) AS passcount,
   sum( if( ECT.rating =0, 1, 0 ) ) AS retakecount,
   sum( if( ECT.rating IS NULL , 1, 0 ) ) AS totakecount,
   L.locationname
FROM employee E,
   location L
INNER JOIN emplcoursetaken ECT ON E.id = ECT.employee_id
RIGHT JOIN courses C ON C.id = ECT.course_id
WHERE C.linkready =1
AND E.location_id = L.id
GROUP BY E.id
ORDER BY L.locationname, E.surname, E.firstname;

它有效。我得到了一组像这样的行:

620 Johnny  Test        12  0   14  Chicago

约翰尼参加了 26 门课程中的 12 门,并通过了这 12 门课程。

但我无法将此查询移动到 ANSI-92 (MySQL 5.1.55)。

SELECT E.id,
   E.firstname, E.surname, E.suffix,
   sum( if( ECT.rating =1, 1, 0 ) ) AS passcount,
   sum( if( ECT.rating =0, 1, 0 ) ) AS retakecount,
   sum( if( ECT.rating IS NULL , 1, 0 ) ) AS totakecount,
   L.locationname
FROM employee E
INNER JOIN emplcoursetaken ECT ON E.id = ECT.employee_id
RIGHT JOIN courses C ON C.id = ECT.course_id
INNER JOIN location L ON E.location_id = L.id
WHERE C.linkready =1
GROUP BY E.id
ORDER BY L.locationname, E.surname, E.firstname;

这个数据库的课程表中只有九门课程,所以我应该得到一个不同的非零“totakecount”值:

620 Johnny  Test    NULL    1   0   0   Chicago 

totakecount 列中应该有一个“8”。取而代之的是零。作为一个实验,我将“RIGHT”更改为“INNER”,并得到了相同的结果。所以我的语法显然有问题,但我的网络搜索并没有告诉我什么。

谢谢。

4

2 回答 2

1

在 MySQL 5.5.30 上测试:

SELECT E.id,
   E.firstname, E.surname, E.suffix,
   sum( if( ECT.rating =1, 1, 0 ) ) AS passcount,
   sum( if( ECT.rating =0, 1, 0 ) ) AS retakecount,
   sum( if( ECT.rating IS NULL , 1, 0 ) ) AS totakecount,
   L.locationname
FROM
courses C 
CROSS JOIN employee E
INNER JOIN location L ON E.location_id = L.id
LEFT JOIN emplcoursetaken ECT ON E.id = ECT.employee_id AND C.id = ECT.course_id
WHERE C.linkready =1
GROUP BY E.id
ORDER BY L.locationname, E.surname, E.firstname;

+----+-----------+---------+--------+-----------+-------------+-------------+--------------+
| id | firstname | surname | suffix | passcount | retakecount | totakecount | locationname |
+----+-----------+---------+--------+-----------+-------------+-------------+--------------+
|  1 | Johnny    | Test    | NULL   |         8 |           0 |           1 | Chicago      |
+----+-----------+---------+--------+-----------+-------------+-------------+--------------+
于 2013-04-30T01:26:57.933 回答
0

我不确定您的原始查询是 ANSI 89。但是,它使用 a,作为cross join. 只需用交叉连接替换它:

SELECT E.id,
   E.firstname, E.surname, E.suffix,
   sum( if( ECT.rating =1, 1, 0 ) ) AS passcount,
   sum( if( ECT.rating =0, 1, 0 ) ) AS retakecount,
   sum( if( ECT.rating IS NULL , 1, 0 ) ) AS totakecount,
   L.locationname
FROM employee E cross join
   location L
INNER JOIN emplcoursetaken ECT ON E.id = ECT.employee_id
RIGHT JOIN courses C ON C.id = ECT.course_id
WHERE C.linkready =1
AND E.location_id = L.id
GROUP BY E.id
ORDER BY L.locationname, E.surname, E.firstname;

从外观上看,您可以将交叉连接转换为内部连接:

SELECT E.id,
   E.firstname, E.surname, E.suffix,
   sum( if( ECT.rating =1, 1, 0 ) ) AS passcount,
   sum( if( ECT.rating =0, 1, 0 ) ) AS retakecount,
   sum( if( ECT.rating IS NULL , 1, 0 ) ) AS totakecount,
   L.locationname
FROM employee E join
   location L
   on E.location_id = L.id
INNER JOIN emplcoursetaken ECT ON E.id = ECT.employee_id
RIGHT JOIN courses C ON C.id = ECT.course_id
WHERE C.linkready =1
GROUP BY E.id
ORDER BY L.locationname, E.surname, E.firstname;

你的评论很有趣。我认为cross join并且,在语义上是相同的。这在历史上是正确的,但现在不是(如此所述):

以前,逗号运算符 (,) 和 JOIN 的优先级相同,因此连接表达式 t1, t2 JOIN t3 被解释为 ((t1, t2) JOIN t3)。现在 JOIN 具有更高的优先级,因此表达式被解释为 (t1, (t2 JOIN t3))。此更改会影响使用 ON 子句的语句,因为该子句只能引用连接操作数中的列,并且优先级的更改会更改对这些操作数的解释。

如果是这种情况,那么括号应该解决优先级问题:

FROM (employee E cross join
      location L
     ) el
    INNER JOIN emplcoursetaken ECT ON El.id = ECT.employee_id

唯一的问题是别名问题。. . 您可能需要将它们更改为el.

于 2013-04-29T23:52:25.810 回答