一个复杂的SQL查询 (想了半天实在想出来了,本人目前已经非常的疼苦 求解惑,付费有偿,逻辑正确,必采纳。)
表数据为:
题目所需字段
CARD_ID(身份证)、TNAME(姓名) 、SCORES(分数)、OPENID(设备ID) 、INSERTTIME(提交成绩时间)
题目要求:
分数>=60分视为考试通过,有一次通过即为考核通过 OPENID重复的两个人视为一个人替另外一个人代考,设定第一次在某设备上提交成绩的人员为A,后续在该设备提交的成绩均为A帮助其他人员代考,成绩应为A的成绩,查询有哪几个人员帮助他人代考,这些人员的考核最高分是多少?结果列输出姓名、考核最高分。
我是这样写的
SELECT
dbo.Test.TNAME,a.OPENID,a.SCORES,a.INSERTTIME
FROM dbo.Test
JOIN (
SELECT
OPENID,MIN(INSERTTIME)AS INSERTTIME,MAX(SCORES) AS SCORES
FROM dbo.Test
GROUP BY OPENID
HAVING COUNT(OPENID)>1
) AS a
ON dbo.Test.OPENID=a.OPENID AND a.INSERTTIME = Test.INSERTTIME
但是里面的数据还有空(陈十二),我不知道这么排除空,还有姓名是重复的(张三),所以这条SQL就不对了。
请各位老哥解惑,这SQL要怎么写啊。 SQL逻辑正确了,付费有偿!
为空你是想怎么排除,是不统计吗?张三是重复的,但证件号和设备ID都相同,应该认为是同一个人,不应该算代考,需要排除不进行统计。
思路:第一步,凡是自己的考试记录,统统去掉,凡是自己帮别人考的统统保留,最终得到代考记录,以及考试设备;第二步,从代考设备上取第一次提交记录就是有帮助他人代考的人,代考设备上的最高分就是这个人的最高分。
如果有用,望采纳,谢谢!
SELECT TEST.TNAME,
A.OPENID,
A.SCORES,
A.INSERTTIME
FROM TEST
JOIN (SELECT OPENID, -- 代考设备
MIN(INSERTTIME) AS INSERTTIME, -- 该设备的最小提交时间,认定为自己考的
MAX(SCORES) AS SCORES -- 该设备上提交的最高分数
FROM TEST
WHERE OPENID IN
(SELECT T1.OPENID --找出有代考行为的设备
FROM TEST T1
INNER JOIN TEST T2
ON T1.OPENID = T2.OPENID -- 根据设备进行关联,如果关联出多条记录,就说明这台设备提交过多次
WHERE NOT (T1.TNAME = T2.TNAME AND
ISNULL(T1.CARD_ID, '') = ISNULL(T2.CARD_ID, '')) -- 排除同一个人的提交,会排除张三的多次提交,也会排除自己提交的所有记录
) --这里保留下来的都是代考记录
GROUP BY OPENID
HAVING COUNT(*) > 1 -- 这个Having其实可以不要了,因为本身就是有代考的记录
) AS A
ON TEST.OPENID = A.OPENID -- 代考设备
AND A.INSERTTIME = TEST.INSERTTIME -- 代考设备上的最早提交时间,本人的考试记录
SELECT
dbo.Test.TNAME,a.OPENID,a.SCORES,a.INSERTTIME
FROM dbo.Test
JOIN (
SELECT
OPENID,MIN(INSERTTIME)AS INSERTTIME,MAX(SCORES) AS SCORES
FROM dbo.Test
WHERE a.tname IS NOT NULL AND a.tname != ''
GROUP BY OPENID
ORDER BY SCORES DESC LIMIT 0,1
HAVING COUNT(OPENID)>1
) AS a
ON dbo.Test.OPENID=a.OPENID AND a.INSERTTIME = Test.INSERTTIME
修改了下sql,可以参考注释理解
SELECT
(select tname from Test t1
where t1.openid=a.openid
and t1.inserttime=a.min_INSERTTIME limit 1) as tname,/*第一次答题的人*/
a.max_scores /*最高分*/
FROM (
select distinct
OPENID,MIN(INSERTTIME)AS min_INSERTTIME,MAX(SCORES) AS max_SCORES
FROM Test
where cardid is not null and cardid <> '' /*排除空值*/
GROUP BY OPENID
having count(openid)>1
) AS a
CARD_ID为NULL的你是准备排除还是利用同名的CARD_ID填充?
有问题可以交流
SELECT
dbo.Test.TNAME,a.OPENID,a.SCORES,a.INSERTTIME
FROM dbo.Test
JOIN (
SELECT
OPENID,MIN(INSERTTIME)AS INSERTTIME,MAX(SCORES) AS SCORES
FROM dbo.Test
WHERE a.tname IS NOT NULL AND a.tname != ''
GROUP BY OPENID
HAVING COUNT(OPENID)>1
) AS a
ON dbo.Test.OPENID=a.OPENID AND a.INSERTTIME = Test.INSERTTIME
做法:
过滤出分数>=60的记录
通过对OPENID进行分组, 将重复的记录归为同一组
查询每组的最高分并输出姓名、考核最高分
仅供参考:
SELECT TNAME, MAX(SCORES)
FROM (
SELECT CARD_ID, TNAME, MIN(INSERTTIME) AS first_submit_time
FROM table
WHERE SCORES >= 60
GROUP BY CARD_ID, TNAME, OPENID
) t1
JOIN table t2
ON t1.CARD_ID = t2.CARD_ID AND t1.first_submit_time = t2.INSERTTIME
GROUP BY t1.TNAME;
这个查询语句可能需要根据数据表结构进行调整
仅供参考,望采纳,谢谢。
是mysql吗?, 测试数据用代码的形式发出来, 便于测试
数据还有空(陈十二),要排除的话加一个card_id is not null的条件就可以了
首先来说说问题,这个问题其实并不复杂,表面上看你的sql逻辑没有什么问题,但是分析数据,你这条sql 基本无法实现这个需求,
先说问题:
1)陈十二 的ID 为空,这个join时 直接过滤掉 ID 为空就行
2) 第二个问题:张三出现两次 ,这个就看你的业务 从数据来看,张三 使用自己的账号考试两次,所以结果为两次,还有一个隐藏问题,如果张三给李四在同一天代考,比如考了90是最高分,结果会返回 张三 和李四都考了90分,问题的根源在于 inserttime 是年月日,数据都在同一天的话,dbo.Test.OPENID=a.OPENID AND a.INSERTTIME = Test.INSERTTIME 这个条件无法确认到人员的唯一性
1、我在MySQL5.7中模拟题主的数据,使用题主的SQL并未输出陈十二的数据(不知道是否模拟数据不全的原因),题主的意思是需要包含陈十二还是需要排除呢?
2、张三和林八均是同一人(card_id相同)在同一设备上考了两次,是需要排序这种情况吗?
那可以使用如下SQL:
SELECT a.TNAME, b.OPENID, b.SCORES, b.INSERTTIME
FROM dbo.test a JOIN ( SELECT OPENID, MIN( INSERTTIME ) AS INSERTTIME, MAX( SCORES ) AS SCORES
FROM dbo.test
GROUP BY OPENID
HAVING COUNT( DISTINCT card_id ) > 1 ) AS b
ON a.OPENID = b.OPENID AND a.INSERTTIME = b.INSERTTIME
输出结果:
3、建议题主最好在给出模拟数据的同时再给出想要结果数据,以便于大家明确最终的输出目标数据是什么