【SQL实战】期末考试,如何统计学生成绩

数据库133

【SQL实战】期末考试,如何统计学生成绩

年底临近,这两天各小学都进入期末考试阶段了。考试结束,就要对学生成绩进行统计。有趣的是,现在学校提供的成绩单上不直接写明分数了,而是一个等级,例如:优秀、良好、合格、不及格。至少北京是这样子的。
言归正传,我们怎么根据成绩表来统计优良差呢?

drop table test_score, test_subject;

-- 学生考试成绩表(学生、科目、成绩)。这里为了方便测试,直接使用临时表

create temporary table test_score
select '张小明' as name, 'Chinese' as 'subject', 89.5 as 'score' union all
SELECT '佩奇', 'Chinese', 100 UNION ALL
SELECT '小哪吒', 'Chinese', 38 UNION ALL
SELECT '乔治', 'Chinese', 95 UNION ALL
SELECT '乔治', 'English', 55 UNION ALL
SELECT '米小圈', 'English', 82 UNION ALL
select '佩奇', 'English', 98 ;

select * from test_score;

name subject score
乔治 Chinese Excellent
乔治 English Lost
佩奇 Chinese Excellent
佩奇 English Excellent
小哪吒 Chinese Lost
张小明 Chinese Excellent
米小圈 English Good

-- §§§【语文老师需要统计语文成绩优良差的学生人数】

select sum(case when score>85 then 1 else 0 end) as 'Excellent'
, SUM(CASE WHEN score>=60 and score

Excellent Good Lost
Chinese 3 0 1
English 1 1 1

-- §§§【增加统计难度----->语文老师要统计语文成绩优良差的人数,并统计各档的总成绩 和 平均成绩】

-- ** 这时,我们再用上面的sql就显得吃力了。 办法总比困难多, 看下面的SQL
select CASE WHEN score>85 THEN 'Excellent'
WHEN score>=60 AND score

Level 总人数 总成绩 平均成绩
佩奇 2 198.0

Original: https://www.cnblogs.com/buguge/p/15788331.html
Author: buguge
Title: 【SQL实战】期末考试,如何统计学生成绩



相关阅读1

Title: jdbc-实现用户登录业务(存在sql注入)

package com.cqust;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

//模拟用户登录,验证成功还是失败
public class JDBCTest05 {
public static void main(String[] args) throws Exception {
//初始化界面,返回用户输入的信息,使用map集合存储
Map

}

/**
 * 用户登录界面
 * @return 返回用户的信息,存在集合中
 */
public static Map<string,string> initLogin(){
    Map<string,string> userInfo = new HashMap<>();
    System.out.print("&#x8BF7;&#x8F93;&#x5165;&#x4F60;&#x7684;&#x7528;&#x6237;&#x540D;:");
    Scanner scanner = new Scanner(System.in);
    String username =  scanner.next();
    System.out.print("&#x8BF7;&#x8F93;&#x5165;&#x4F60;&#x7684;&#x5BC6;&#x7801;:");
    String userpwd = scanner.next();
    userInfo.put("username",username);
    userInfo.put("userpwd",userpwd);

    return userInfo;
}

/**
 * &#x4F7F;&#x7528;jdbc&#x6280;&#x672F;&#x5B8C;&#x6210;&#x767B;&#x5F55;&#x68C0;&#x6D4B;
 * @param map &#x7528;&#x6237;&#x7684;&#x4FE1;&#x606F;&#x5B58;&#x50A8;&#x5728;&#x96C6;&#x5408;map&#x4E2D;
 * @return  &#x6700;&#x540E;&#x8FD4;&#x56DE;&#x767B;&#x5F55;&#x6210;&#x529F;&#x8FD8;&#x662F;&#x5931;&#x8D25;
 * @throws Exception &#x8FD9;&#x91CC;&#x4E3A;&#x4E86;&#x7701;&#x70B9;&#x52B2;&#x76F4;&#x63A5;throws
 */
public static boolean login(Map<string,string> map) throws Exception{
    String username = map.get("username");
    String userpwd = map.get("userpwd");
    boolean loginInfo = false;
    //1.&#x6CE8;&#x518C;&#x9A71;&#x52A8;
    Class.forName("com.mysql.jdbc.Driver");
    //2.&#x83B7;&#x53D6;&#x8FDE;&#x63A5;
    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/cqust_db",
            "root","hch1");
    //3.&#x83B7;&#x53D6;&#x6570;&#x636E;&#x5E93;&#x64CD;&#x4F5C;&#x5BF9;&#x8C61;
    Statement statement = connection.createStatement();

    //4.&#x5199;sql&#xFF0C;&#x6267;&#x884C;sql
    String sql = "select username,userpwd from t_user_login where username = '"+username+"' and userpwd = '"+userpwd+"'";

    ResultSet resultSet = statement.executeQuery(sql);
    //5.&#x8FD9;&#x91CC;&#x53EA;&#x9700;&#x8981;&#x770B;&#x662F;&#x5426;&#x6709;&#x6570;&#x636E;&#xFF0C;&#x5982;&#x679C;&#x67E5;&#x8BE2;&#x5230;&#x6570;&#x636E;&#xFF0C;&#x5219;&#x767B;&#x5F55;&#x6210;&#x529F;&#xFF0C;&#x76F4;&#x63A5;loginInfo = true;
    if (resultSet.next()){
        loginInfo = true;

    }

    //6.&#x5173;&#x95ED;&#x8D44;&#x6E90;
    if (resultSet!=null){
        resultSet.close();
    }
    if (statement!=null){
        statement.close();
    }

    if (connection!=null){
        connection.close();
    }

    return loginInfo;
}
</string,string></string,string></string,string>

}

Original: https://www.cnblogs.com/journeyhch/p/15573926.html
Author: journeyhch
Title: jdbc-实现用户登录业务(存在sql注入)

相关阅读2

Title: 三分钟图解 MVCC,看一遍就懂

前文我们介绍了 InnoDB 存储引擎在事务隔离级别 READ COMMITTED 和 REPEATABLE READ(默认)下会开启一致性非锁定读,简单回顾下:所谓一致性非锁定读就是每行记录可能存在多个历史版本,多版本之间串联起来形成了一条版本链,这样不同时刻启动的事务可以 无锁地访问到不同版本的数据。

undo log 版本链

一致性非锁定读是通过 MVCC(Multi Version Concurrency Control,多版本并发控制) 来实现的。事实上,MVCC 没有一个统一的实现标准,所以各个存储引擎的实现机制不尽相同。

InnoDB 存储引擎中 MVCC 的实现是通过 undo log 来完成的,undo log 是啥?

简单理解, undo log 就是每次操作的反向操作,比如比如当前事务执行了一个插入 id = 100 的记录的操作,那么 undo log 中存储的就是删除 id = 100 的记录的操作。

所以,这里用多版本来形容并不是非常准确,因为 InnoDB 并不会真正地去开辟空间存储多个版本的行记录,只是借助 undo log 记录每次写操作的反向操作。

也就是说,B+ 索引树上对应的记录只会有一个最新版本,只不过 InnoDB 可以 根据 undo log 得到数据的历史版本,从而实现多版本控制。

【SQL实战】期末考试,如何统计学生成绩

那么,还有个问题,undo log 是如何和某条行记录产生联系的呢?换句话说,我怎么能通过这条行记录找到它拥有的 undo log 呢?

具体来说, InnoDB 存储引擎中每条行记录其实都拥有两个隐藏的字段: trx_idroll_pointer

从名字也能看出来, trx_id 就是最近更新这条行记录的事务 ID, roll_pointer 就是指向之前生成的 undo log。

掏出我们的 user 表,来举个例子,假设 id = 100 的事务 A 插入一条行记录(id = 1, username = "Jack", age = 18),那么,这行记录的两个隐藏字段 trx_id = 100roll_pointer 指向一个空的 undo log,因为在这之前并没有事务操作 id = 1 的这行记录。如图所示:

【SQL实战】期末考试,如何统计学生成绩

然后,id = 200 的事务 B 修改了这条行记录,把 age 从 18 修改成了 20,于是,这条行记录的 trx_id 就变成了 200, rooll_pointer 就指向事务 A 生成的 undo log :

【SQL实战】期末考试,如何统计学生成绩

接着,id = 300 的事务 C 再次修改了这条行记录,把 age 从 20 修改成了 30,如下图:

【SQL实战】期末考试,如何统计学生成绩

可以看到,每次修改行记录都会更新 trx_id 和 roll_pointer 这两个隐藏字段,之前的多个数据快照对应的 undo log 会通过 roll_pointer 指针串联起来,从而形成一个 版本链

需要注意的是, select 查询操作不会生成 undo log!在 InnoDB 存储引擎中,undo log 只分为两种:

  • insert undo log:在 insert 操作中产生的 undo log
  • update undo log:对 delete 和 update 操作产生的 undo log

事实上,由于事务隔离性的要求,insert 操作的记录,只对事务本身可见,对其他事务不可见,对吧,所以也就不存在并发情况下的问题。所以,也就是说, MVCC 这个机制,其实就是靠 update undo log 实现的,和 insert undo log 基本上没啥关系,我们上面说的 undo log 版本链上的其实就是 update undo log。

ReadView 机制

说到 MVCC,说到 undo log 版本链,如果你自己不往下说的话,八九不离十面试官都会问你下 ReadView 这个机制。

咱也不卖官子,直接说吧, ReadView 机制就是用来判断当前事务能够看见哪些版本的,一个 ReadView 主要包含如下几个部分:

  • m_ids:生成 ReadView 时有哪些事务在执行但是还没提交的(称为 " 活跃事务"),这些活跃事务的 id 就存在这个字段里
  • min_trx_id:m_ids 里最小的值
  • max_trx_id:生成 ReadView 时 InnoDB 将分配给下一个事务的 ID 的值(事务 ID 是递增分配的,越后面申请的事务 ID 越大)
  • creator_trx_id:当前创建 ReadView 事务的 ID

接下来,再掏出 user 表,通过一个例子来理解下 ReaView 机制是如何做到判断当前事务能够看见哪些版本的:

假设表中已经被之前的事务 A(id = 100)插入了一条行记录(id = 1, username = "Jack", age = 18),如图所示:

【SQL实战】期末考试,如何统计学生成绩

接下来,有两个事务 B(id = 200) 和 C(id = 300)过来 并发执行,事务 B 想要更新(update)这行 id = 1 的记录,而事务 C(select)想要查询这行数据,这两个事务都执行了相应的操作但是还没有进行提交:

【SQL实战】期末考试,如何统计学生成绩

如果现在事务 B 开启了一个 ReadView,在这个 ReadView 里面:

  • m_ids 就包含了当前的活跃事务的 id,即事务 B 和事务 C 这两个 id,200 和 300
  • min_trx_id 就是 200
  • max_trx_id 是下一个能够分配的事务的 id,那就是 301
  • creator_trx_id 是当前创建 ReadView 事务 B 的 id 200

【SQL实战】期末考试,如何统计学生成绩

现在事务 B 进行第一次查询(上面说过 select 操作不会生成 undo log 的哈),会 把这行记录的隐藏字段 trx_id 和 ReadView 的 min_trx_id 进行下判断,此时,发现 trx_id 是 100,小于 ReadView 里的 min_trx_id(200),这说明在事务 B 开始之前,修改这行记录的事务 A 已经提交了,所以 开始于事务 A 提交之后的事务 B、是可以查到事务 A 对这行记录的更新的

row.trx_id < ReadView.min_trx_id

【SQL实战】期末考试,如何统计学生成绩

接着事务 C 过来修改这行记录,把 age = 18 改成了 age = 20,所以这行记录的 trx_id 就变成了 300,同时 roll_pointer 指向了事务 C 修改之前生成的 undo log:

【SQL实战】期末考试,如何统计学生成绩

那这个时候事务 B 再次进行查询操作,会发现 这行记录的 trx_id (300)大于 ReadView 的 min_trx_id (200),并且小于 max_trx_id (301)

row.trx_id > ReadView.min_trx_id && row.trx_id < max_trx_id

这说明一个问题,就是更新这行记录的事务很有可能也存在于 ReadView 的 m_ids(活跃事务)中。所以事务 B 会去判断下 ReadView 的 m_ids 里面是否存在 trx_id = 300 的事务,显然是存在的,这就表示这个 id = 300 的事务是跟自己(事务 B)在同一时间段并发执行的事务,也就说明这行 age = 20 的记录事务 B 是不能查询到的。

【SQL实战】期末考试,如何统计学生成绩

既然无法查询,那该咋整?事务 B 这次的查询操作能够查到啥呢?

没错,undo log 版本链!

这时事务 B 就会顺着这行记录的 roll_pointer 指针往下找,就会找到最近的一条 trx_id = 100 的 undo log,而自己的 id 是 200,即说明这个 trx_id = 100 的 undo log 版本必然是在事务 B 开启之前就已经提交的了。所以事务 B 的这次查询操作读到的就是这个版本的数据即 age = 18。

通过上述的例子,我们得出的结论是, 通过 undo log 版本链和 ReadView 机制,可以保证一个事务不会读到并发执行的另一个事务的更新

那自己修改的值,自己能不能读到呢?

这当然是废话,肯定可以读到呀。不过上面的例子我们只涉及到了 ReadView 中的前三个字段,而 creator_trx_id 就与自己读自己的修改有关,所以这里还是图解出来让大家更进一步理解下 ReadView 机制:

假设事务 C 的修改已经提交了,然后事务 B 更新了这行记录,把 age = 20 改成了 age = 66,如下图所示:

【SQL实战】期末考试,如何统计学生成绩

然后,事务 B 再来查询这条记录,发现 trx_id = 200 与 ReadView 里的 creator_trx_id = 200 一样,这就说明这是我自己刚刚修改的啊,当然可以被查询到。

row.trx_id = ReadView.creator_trx_id

【SQL实战】期末考试,如何统计学生成绩

那如果在事务 B 的执行期间,突然开了一个 id = 400 的事务 D,然后更新了这行记录的 age = 88 并且还提交了,然后事务 B 再去读这行记录,能读到吗?

【SQL实战】期末考试,如何统计学生成绩

答案是不能的。

因为这个时候事务 B 再去查询这行记录,就会发现 trx_id = 500 大于 ReadView 中的 max_trx_id = 301,这说明事务 B 执行期间,有另外一个事务更新了数据,所以不能查询到另外一个事务的更新。

row.trx_id > ReadView.max_trx_id

【SQL实战】期末考试,如何统计学生成绩

那通过上述的例子,我们得出的结论是, 通过 undo log 版本链和 ReadView 机制,可以保证一个事务只可以读到该事务自己修改的数据或该事务开始之前的数据

小结

总结下,通过 undo log 版本链和 ReadView 机制:

  • 可以保证一个事务不会读到并发执行的另一个事务的更新
  • 可以保证一个事务只可以读到该事务自己修改的数据或该事务开始之前的数据

另外,前文说过,一致性非锁定读(或者直接说 MVCC 吧,毕竟一致性非锁定读也是靠 MVCC 实现的)只在事务隔离级别 READ COMMITTED 和 REPEATABLE READ(默认)下才会开启,那对于这两个隔离级别,其实最根本的不同之处,就在于它们 生成 ReadView 的时机不同,这个我们留在下文解释~

🎉 关注公众号 | 飞天小牛肉,即时获取更新

  • 博主东南大学硕士在读,携程 Java 后台开发暑期实习生,利用课余时间运营一个公众号『 飞天小牛肉 』,2020/12/29 日开通,专注分享计算机基础(数据结构 + 算法 + 计算机网络 + 数据库 + 操作系统 + Linux)、Java 技术栈等相关原创技术好文。关注公众号第一时间获取文章更新, 后台回复 300 即可免费获取极客大学出品的 Java 面试 300 题
  • 并推荐个人维护的开源教程类项目: CS-Wiki(Gitee 推荐项目,现已累计 1.8k+ star), 致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习 ~ 😊
  • 如果各位小伙伴春招秋招没有拿得出手的项目的话,可以参考我写的一个项目「开源社区系统 Echo」Gitee 官方推荐项目,目前已累计 900+ star,基于 SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ... 并提供详细的开发文档和配套教程。公众号后台回复 Echo 可以获取配套教程,目前尚在更新中。

Original: https://www.cnblogs.com/cswiki/p/15338928.html
Author: 飞天小牛肉
Title: 三分钟图解 MVCC,看一遍就懂

相关阅读3

Title: 我应该是最后一个知道 WSL 的吧!

前言

前段时间,我买了块固态硬盘给我的笔记本电脑装上(因为它太慢了,影响我游戏学习)。同时也重装了系统,以前一直在用 Win8.1,在上面构建了我的开发环境:在 Win8.1 上安装了 VMvare,在 VMware 上安装了 Centos,在 Centos 上安装了 Docker,然后在 Win8.1 上通过 Xshell 来连接虚拟机 Centos 控制 Docker 进行开发学习。
【SQL实战】期末考试,如何统计学生成绩

这次安装的是 Win10,真香,win10 支持了 WSL,直接可以在 Win10 上安装 Docker、Linux系统等,因此重新搭建了我的开发环境,首先把 Git 配置好。

什么是 WSL

WSL 是 Windows Subsystem for Linux 的缩写,意思是 linux 版的 window 子系统。

引用自:微软官网 https://docs.microsoft.com/zh-cn/windows/wsl/about
The Windows Subsystem for Linux lets developers run a GNU/Linux environment -- including most command-line tools, utilities, and applications -- directly on Windows, unmodified, without the overhead of a virtual machine.

You can:

  • Choose your favorite GNU/Linux distributions from the Microsoft Store.

  • Run common command-line tools such as grep, sed, awk, or other ELF-64 binaries.

  • Run Bash shell scripts and GNU/Linux command-line applications including:

  • Install additional software using own GNU/Linux distribution package manager.

  • Invoke Windows applications using a Unix-like command-line shell.

  • Invoke GNU/Linux applications on Windows.

简单的说就是,Linux 的 Windows 子系统让开发人员无需虚拟机就可以直接在 Windows 上运行 Linux 环境,包括大多数命令行工具、程序和应用。
使用 WSL 的好处是:

  1. 与在虚拟机下使用 Linux 相比,WSL 占用资源更少,更加流畅;
  2. WSL 可以对 Windows 文件系统下的文件直接进行读写,文件传输更方便;
  3. 剪贴板互通,可以直接在 Windows 下其它地方复制文本内容,粘贴到 WSL;
    【SQL实战】期末考试,如何统计学生成绩

WSL 安装 Ubuntu

  1. 通过 Microsoft Store下载,自动安装
    【SQL实战】期末考试,如何统计学生成绩
  2. 自己去官网下载,防止 C 盘容量太大
    官网
    【SQL实战】期末考试,如何统计学生成绩
    下载后复制到 D盘,将后缀名改成 .zip,然后解压,执行里面的 exe文件,进行安装

安装后在 powershell或者 windows terminal(Microsoft Store上的另一个宝藏应用,直接去搜扫安装就行了)
执行命令 wsl -l -v 列出所有子系统

PS C:\Users\Administrator> wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu-20.04           Running         2
  docker-desktop         Stopped         2
  docker-desktop-data    Stopped         2

执行命令 wslconfig /setdefault Ubuntu-20.04Ubunru-20.04设为默认子系统

PS C:\Users\Administrator> wslconfig /setdefault Ubuntu-20.04

执行命令 wsl进入子系统

PS C:\Users\Administrator> wsl
zioyi@DESKTOP-Q4DJEQV:/mnt/c/Users/Administrator$ neofetch

【SQL实战】期末考试,如何统计学生成绩

配置 zsh

查看一下

zioyi@DESKTOP-Q4DJEQV:/mnt/c/Users/Administrator$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash
/usr/bin/tmux
/usr/bin/screen

安装 zsh

zioyi@DESKTOP-Q4DJEQV:/mnt/c/Users/Administrator$ sudo apt-get install zsh
zioyi@DESKTOP-Q4DJEQV:/mnt/c/Users/Administrator$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash
/usr/bin/tmux
/usr/bin/screen
/bin/zsh
/usr/bin/zsh

将 zsh 设为默认 shell

zioyi@DESKTOP-Q4DJEQV:/mnt/c/Users/Administrator$ sudo chsh -s /bin/zsh

推出再重新进入

zioyi@DESKTOP-Q4DJEQV:/mnt/c/Users/Administrator$ exit
logout
PS C:\Users\Administrator> wsl
&#x279C;  Administrator neofetch

配置 Git

  1. 安装 git
➜  Administrator sudo apt-get install git
  1. 配置你的用户名
➜  Administrator git config --global user.name xxx
  1. 配置你的邮箱地址
➜  Administrator git config --global user.email  xxx@xxx.com
  1. 生产SSH密钥
➜  Administrator ssh-keygen -t rsa -C "xxx@xxx.com"
➜  Administrator cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC12sKF6l8CKsYjrWCruS3fqPhSHExo6pcvzCRUYMotqY7KJvhIG45xGALedXn8ow8+jBfC6r9CpO6mzCpf18WsGf7omBvoQJa3rQeuO1KvZ7Ctd/EH+jJndLoFisH76vY4gm2OR0UU= xxx@xxx.com
  1. 复制公钥的内容并且打开你的 github 设置界面,找到 SSHkey 设置,点击右上角的New SSH key
    【SQL实战】期末考试,如何统计学生成绩

6.测试

➜  Administrator ssh git@github.com
PTY allocation request failed on channel 0
Hi Zioyi! You've successfully authenticated, but GitHub does not provide shell access.

Connection to github.com closed.

总结

本篇对 WSL 进行了简单介绍,尝试基于 WSL 安装了 Ubuntu 系统,并在系统中安装 zsh 和 git 工具,打造新时代的 Windows 开发环境。
相比于原来 Win8 的开发环境,这套真的好很多,在便捷性、资源使用、性能上都有很大的提升。

Original: https://www.cnblogs.com/Zioyi/p/15230350.html
Author: Zioyi
Title: 我应该是最后一个知道 WSL 的吧!