执行摘要:在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
应该有一个' 8'在totakecount列中。而不是那里 零。作为一项实验,我改变了" RIGHT"到" INNER"和 得到了相同的结果。所以我明显做错了 语法,但我的网络搜索并没有告诉我什么。
感谢。
答案 0 :(得分: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 |
+----+-----------+---------+--------+-----------+-------------+-------------+--------------+
答案 1 :(得分:0)
我不确定您的原始查询是否为ANSI 89.但是,它使用,
作为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
和,
在语义上是相同的。这在历史上是正确的,但现在不是(如here所述):
以前,逗号运算符(,)和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
。