一个复杂的SQL查询 (想了半天实在想出来了,本人目前已经非常的疼苦 求解惑,付费有偿,逻辑正确,必采纳。)

一个复杂的SQL查询 (想了半天实在想出来了,本人目前已经非常的疼苦 求解惑,付费有偿,逻辑正确,必采纳。)
表数据为:

img

题目所需字段
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的条件就可以了

img

首先来说说问题,这个问题其实并不复杂,表面上看你的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

输出结果:

img

3、建议题主最好在给出模拟数据的同时再给出想要结果数据,以便于大家明确最终的输出目标数据是什么