MYSQL 加入子查询问题
MYSQL joining subquery issue
我有一个 table 里面有人们的成绩。
+---------+--------+--------+--------+---------------------+
| name | grade1 | grade2 | grade3 | datetime |
+---------+--------+--------+--------+---------------------+
| person1 | 50 | 80 | 100 | 2015-05-05 12:00:00 |
| person1 | 60 | 43 | 88 | 2015-05-05 12:00:00 |
| person1 | 11 | 80 | 44 | 2015-05-05 12:00:00 |
| person1 | 64 | 75 | 37 | 2015-05-05 12:00:00 |
| person1 | 83 | 34 | 99 | 2015-05-05 12:00:00 |
| person2 | 45 | 100 | 95 | 2015-05-05 12:00:00 |
| person2 | 76 | 75 | 54 | 2015-05-05 12:00:00 |
| person2 | 68 | 53 | 66 | 2015-05-05 12:00:00 |
| person2 | 45 | 12 | 85 | 2015-05-05 12:00:00 |
| person2 | 75 | 78 | 55 | 2015-05-05 12:00:00 |
+---------+--------+--------+--------+---------------------+
我需要做的是提取一个人在特定日期的成绩,然后提取一个字符串来表示他们 pass/fail 前(最多 7)天的报告。
我根据 table 寻找的最终结果将是这样的:
+---------------+---------+--------+--------+--------+----------------+
| report | name | grade1 | grade2 | grade3 | datetime |
+---------------+---------+--------+--------+--------+----------------+
| pass:3 fail:2 | person1 | 50 | 80 | 100 | 5/5/2015 12:00 |
| pass:2 fail:3 | person2 | 42 | 100 | 95 | 5/5/2015 12:00 |
+---------------+---------+--------+--------+--------+----------------+
所以我 sql 获得第一部分非常简单:
SELECT *
FROM Grades.grade_table gt
WHERE gt.datetime = '2015-05-05 12:00:00'
我的查询的第二部分如下所示:
SELECT CONCAT('fail:',SUM(CASE WHEN pass_fail = 'fail' THEN 1 ELSE 0 END),' pass:',SUM(CASE WHEN pass_fail = 'pass' THEN 1 ELSE 0 END)) trend_data
FROM (
SELECT
CASE
WHEN ((grade1+grade2+grade3)/3) >= 65 THEN 'pass'
ELSE 'fail'
END AS pass_fail
FROM Grades.grade_table gt
WHERE gt.name = 'person1'
LIMIT 7
) trend_data
我尝试过的:
SELECT
(
SELECT CONCAT('fail:',SUM(CASE WHEN pass_fail = 'fail' THEN 1 ELSE 0 END),' pass:',SUM(CASE WHEN pass_fail = 'pass' THEN 1 ELSE 0 END)) trend_data
FROM (
SELECT
CASE
WHEN ((grade1+grade2+grade3)/3) >= 65 THEN 'pass'
ELSE 'fail'
END AS pass_fail
FROM Grades.grade_table gt
WHERE gt.name = original_data.name
LIMIT 7
) trend_data
) AS trending_data, original_data.*
FROM
(
SELECT *
FROM Grades.grade_table gt
WHERE gt.datetime = '2015-05-05 12:00:00'
)
我一直无法在 where 子句中找到 original_data.name,但我认为它会通过,因为它在一个单独的 select 中,它是别名的。
我试图重建您的模式并创建一个简单的查询来满足您的需求。
SQLfiddle: http://sqlfiddle.com/#!9/74eb5e/61
获取成功与失败的查询:
SELECT name AS 'Name',
CONCAT(
'Fail: ',
CAST(SUM(CASE WHEN (grade1+grade2+grade3)/3 <= 65 THEN 1 ELSE 0 END) AS CHAR(20)),
' Success: ',
CAST(SUM(CASE WHEN (grade1+grade2+grade3)/3 > 65 THEN 1 ELSE 0 END) AS CHAR(20))) AS 'Report',
NOW() AS 'Report date'
FROM grade_table gt1
WHERE (SELECT COUNT(*)
FROM grade_table
WHERE name = gt1.name
AND gradedate > gt1.gradedate
ORDER BY gradedate ASC) < 7
GROUP BY name;
编辑 1:
新代码和更新的 SQLfiddle 满足您的要求(每个人的失败和成功的最后 7 天)。
编辑 2:
这基本上是一个更复杂的问题,此处有详细描述:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
一般来说,您不能轻易地为此类子句使用 LIMIT,因为您想要限制每个组 (GROUP BY name
)。但是,您可以使用类似这样的方法来获取每组的前 N 条记录:
SELECT name, gradedate
FROM grade_table gt1
WHERE (SELECT COUNT(*)
FROM grade_table
WHERE name = gt1.name
AND gradedate > gt1.gradedate
ORDER BY gradedate ASC) < 2
它将检查组中的特定记录是否有 (COUNT(*)
) 少于两条具有更大(更新)日期的记录。它只是意味着它只能是该记录,也可以是其中一个更大的记录。
我已经更新了最终解决方案,因此它现在应该可以满足您的需求。
请注意,提供的解决方案不是很有效,尽管它可以扩展为 N 个可能的名称。
我建议您阅读所提供的博客,因为文章下方有更多示例和一些很棒的评论,短时间内很难在这里详述。
我有一个 table 里面有人们的成绩。
+---------+--------+--------+--------+---------------------+
| name | grade1 | grade2 | grade3 | datetime |
+---------+--------+--------+--------+---------------------+
| person1 | 50 | 80 | 100 | 2015-05-05 12:00:00 |
| person1 | 60 | 43 | 88 | 2015-05-05 12:00:00 |
| person1 | 11 | 80 | 44 | 2015-05-05 12:00:00 |
| person1 | 64 | 75 | 37 | 2015-05-05 12:00:00 |
| person1 | 83 | 34 | 99 | 2015-05-05 12:00:00 |
| person2 | 45 | 100 | 95 | 2015-05-05 12:00:00 |
| person2 | 76 | 75 | 54 | 2015-05-05 12:00:00 |
| person2 | 68 | 53 | 66 | 2015-05-05 12:00:00 |
| person2 | 45 | 12 | 85 | 2015-05-05 12:00:00 |
| person2 | 75 | 78 | 55 | 2015-05-05 12:00:00 |
+---------+--------+--------+--------+---------------------+
我需要做的是提取一个人在特定日期的成绩,然后提取一个字符串来表示他们 pass/fail 前(最多 7)天的报告。
我根据 table 寻找的最终结果将是这样的:
+---------------+---------+--------+--------+--------+----------------+
| report | name | grade1 | grade2 | grade3 | datetime |
+---------------+---------+--------+--------+--------+----------------+
| pass:3 fail:2 | person1 | 50 | 80 | 100 | 5/5/2015 12:00 |
| pass:2 fail:3 | person2 | 42 | 100 | 95 | 5/5/2015 12:00 |
+---------------+---------+--------+--------+--------+----------------+
所以我 sql 获得第一部分非常简单:
SELECT *
FROM Grades.grade_table gt
WHERE gt.datetime = '2015-05-05 12:00:00'
我的查询的第二部分如下所示:
SELECT CONCAT('fail:',SUM(CASE WHEN pass_fail = 'fail' THEN 1 ELSE 0 END),' pass:',SUM(CASE WHEN pass_fail = 'pass' THEN 1 ELSE 0 END)) trend_data
FROM (
SELECT
CASE
WHEN ((grade1+grade2+grade3)/3) >= 65 THEN 'pass'
ELSE 'fail'
END AS pass_fail
FROM Grades.grade_table gt
WHERE gt.name = 'person1'
LIMIT 7
) trend_data
我尝试过的:
SELECT
(
SELECT CONCAT('fail:',SUM(CASE WHEN pass_fail = 'fail' THEN 1 ELSE 0 END),' pass:',SUM(CASE WHEN pass_fail = 'pass' THEN 1 ELSE 0 END)) trend_data
FROM (
SELECT
CASE
WHEN ((grade1+grade2+grade3)/3) >= 65 THEN 'pass'
ELSE 'fail'
END AS pass_fail
FROM Grades.grade_table gt
WHERE gt.name = original_data.name
LIMIT 7
) trend_data
) AS trending_data, original_data.*
FROM
(
SELECT *
FROM Grades.grade_table gt
WHERE gt.datetime = '2015-05-05 12:00:00'
)
我一直无法在 where 子句中找到 original_data.name,但我认为它会通过,因为它在一个单独的 select 中,它是别名的。
我试图重建您的模式并创建一个简单的查询来满足您的需求。
SQLfiddle: http://sqlfiddle.com/#!9/74eb5e/61
获取成功与失败的查询:
SELECT name AS 'Name',
CONCAT(
'Fail: ',
CAST(SUM(CASE WHEN (grade1+grade2+grade3)/3 <= 65 THEN 1 ELSE 0 END) AS CHAR(20)),
' Success: ',
CAST(SUM(CASE WHEN (grade1+grade2+grade3)/3 > 65 THEN 1 ELSE 0 END) AS CHAR(20))) AS 'Report',
NOW() AS 'Report date'
FROM grade_table gt1
WHERE (SELECT COUNT(*)
FROM grade_table
WHERE name = gt1.name
AND gradedate > gt1.gradedate
ORDER BY gradedate ASC) < 7
GROUP BY name;
编辑 1:
新代码和更新的 SQLfiddle 满足您的要求(每个人的失败和成功的最后 7 天)。
编辑 2:
这基本上是一个更复杂的问题,此处有详细描述:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
一般来说,您不能轻易地为此类子句使用 LIMIT,因为您想要限制每个组 (GROUP BY name
)。但是,您可以使用类似这样的方法来获取每组的前 N 条记录:
SELECT name, gradedate
FROM grade_table gt1
WHERE (SELECT COUNT(*)
FROM grade_table
WHERE name = gt1.name
AND gradedate > gt1.gradedate
ORDER BY gradedate ASC) < 2
它将检查组中的特定记录是否有 (COUNT(*)
) 少于两条具有更大(更新)日期的记录。它只是意味着它只能是该记录,也可以是其中一个更大的记录。
我已经更新了最终解决方案,因此它现在应该可以满足您的需求。 请注意,提供的解决方案不是很有效,尽管它可以扩展为 N 个可能的名称。 我建议您阅读所提供的博客,因为文章下方有更多示例和一些很棒的评论,短时间内很难在这里详述。