Oracle

(一)资源

1. 视频

2. 笔记

3. 函数

(二)简介

1.基础

MySQL + JavaSE + Navicat Premium 16 + Linux

2.资源

搜罗后,相对易入门的

3.声明

是个小白

(三)数据库

1.关系与分布

数据库名称关系型数据库分布式数据库分布式部署
MySQL
Oracle
Redis
MongoDB

关系型:数据之间有联系
分布式:数据分散存储

注:通常关系型数据库并不具备分布式功能,但在后续的集群扩展往往可以实现分布式部署。

2.优势与应用

数据库名称数据组织和存储方式 分布式部署优势(关系型)应用
MySQL 表格MySQL Cluster... 事务处理-复杂查询银行转账-多表关联
OracleOracle RAC...
Redis键值Redis Cluster...实时读写-数据缓存在线游戏-购物车数据
MongoDB文档MongoDB Sharding...

注:分布式部署往往通过集群(Cluster)、分区/片实现

【拓展】
Redis-MongoDB的差异化应用:个性推荐-大数据存储

3.Oracle vs MySQL

1).基础差异

OracleMySQL
数据库安装与连接步骤更多
建库建表各种授权
逻辑/物理结构更复杂
数据文件格式.dbf+…

2).差异展示

(1).看库Oracle:看库z注:Oracle就只有一个大数据库

MySQL:看库

(四)Oracle

1.表空间

1).定义

管理物理存储和分配的基本单元
用于存储数据库对象(例如表和索引)和它们的数据

表空间是 Oracle 对物理数据库上相关数据文件(ORA 或者 DBF 文件)的逻辑映射。一个数据库在逻辑上被划分成一到若干个表空间,每个表空间包含了在逻辑上相关联的一组结构。

2).关系

数据库与表空间表空间与数据文件
1:n1:n

每个表空间由同一磁盘上的一个或多个文件组成,这些文件叫数据文件

一个数据文件只能属于一个表空间

3).结构

既包含物理结构又包含逻辑结构。

从物理上看,表空间由一个或多个数据文件组成,这些数据文件存储了实际的表数据和索引数据等物理数据。
从逻辑上看,表空间是一个由Oracle管理的逻辑存储结构。表空间定义了一个逻辑和物理组合的存储结构,它作为数据库对象(如表、索引和视图等)的存储载体。通过创建不同的表空间,可以为不同的对象和用户提供彼此分离的独立空间,保证了数据安全性和数据隔离性。

【逻辑示意图】:
逻辑示意图逻辑结构

2.用户

1).关系

用户:表空间 = n:m

一个用户可以拥有多个表空间,但是每个用户必须有一个默认的表空间。
多个用户可以共享同一个表空间。

2).类型

自带用户
用户名密码说明权限
scotttiger测试用户CUDR
system次级管理员+创建用户
sys超级管理员+备份和恢复

注:scott等只有对自己创建的对象进行数据操作的权限和部分系统权限

3).指令

连接(cmd) :sqlplus
-- 查看当前使用的数据库(唯一)
SELECT name FROM v$database;
-- 查看当前用户用户名
SELECT USER FROM dual;
-- 查看所有用户用户名
SELECT DISTINCT owner FROM all_tables;
-- 创建新用户
CREATE USER new_user IDENTIFIED BY user_password;
CREATE USER oracleTest IDENTIFIED BY 123456;
-- 重新连接到新用户
CONNECT oracleTest/123456
-- 赋予权限
GRANT DBA TO oracleTest;

#  【表空间】
-- 查看表空间
SELECT * FROM DBA_TABLESPACES;
-- 查看当前用户所属的表空间
SELECT * FROM USER_TABLESPACES;
-- 上述两个结果相同
-- 使用的表空间为数据库中的默认表空间

-- 新建表空间
create tablespace oracleTest
datafile 'c:\oracleTest.dbf'
size 100m
autoextend on
next 10m
-- oracleTest 为表空间名称
-- datafile 用于设置物理文件名称
-- size 用于设置表空间的初始大小
-- autoextend on 用于设置自动增长,如果存储量超过初始大小,则开始自动扩容
-- next 用于设置扩容的空间大小

-- 设置当前用户的表空间
ALTER USER now_user DEFAULT TABLESPACE tablespace_name;
ALTER USER oracleTest DEFAULT TABLESPACE oracleTest;

3.小练习①

1).初始化

-- 创建表
CREATE TABLE jobs (
  jobno NUMBER(2,0) CHECK(jobno >= 0),
  jobname VARCHAR2(10),
  sal DECIMAL(8, 2),
  comm DECIMAL(8, 2) 
);
-- 注释
COMMENT ON TABLE jobs IS '员工表';
COMMENT ON COLUMN jobs.jobno IS 'id';
COMMENT ON COLUMN jobs.jobname IS '姓名';
COMMENT ON COLUMN jobs.sal IS '薪水';
COMMENT ON COLUMN jobs.comm IS '津贴';
-- 插入数据
INSERT INTO jobs (jobno, jobname, sal, comm) VALUES (1, '经理', 5000.00, 500.00);
INSERT INTO jobs (jobno, jobname, sal, comm) VALUES (2, '总经理', 4000.00, 400.00);
INSERT INTO jobs (jobno, jobname, sal, comm) VALUES (3, '部门经理', 3000.00, 300.00);
INSERT INTO jobs (jobno, jobname, sal, comm) VALUES (4, '职员', 2000.00, 200.00);

2).字段对比

MySQLOracle
VARCHARVARCHAR2
jobno int(2) unsignedjobno NUMBER(2,0) check (jobno >= 0)
sysdate()/now()sysdate

3).需求

(1)添加列’hiredate’(入职时间),并插入一条数据:获取当前时间
(2)查询‘部门经理’的年薪(薪水+津贴;四舍五入计算)
(3)查询各个职位的年薪,如果是董事长按15薪统计,总经理按13薪统计

4).参考

SELECT * FROM jobs;
DROP TABLE jobs;
-- 1
ALTER TABLE jobs ADD hiredate DATE;
INSERT INTO jobs (jobno, jobname, sal, comm, hiredate) VALUES (1, 'manager', 5000, 1000, SYSDATE);
-- 2
SELECT ROUND((sal + comm) * 12) AS annual_salary FROM jobs WHERE jobname = '部门经理';
-- 3
SELECT jobname,
       CASE jobno
          WHEN 1 THEN ROUND((sal + comm) * 15)
          WHEN 2 THEN ROUND((sal + comm) * 13)
          ELSE ROUND((sal + comm) * 12)
       END AS annual_salary
FROM jobs;

4.JDBC:增删改

1).软件

Eclipse + Navicat + Oracle11 + jdk1.8 +ojdbc14.jar

2).思路

3).SQL

(1).表信息

在这里插入图片描述

(2).建表语句
CREATE TABLE T_OWNERS(
ID NUMBER PRIMARY KEY,
NAME VARCHAR2(30),
ADDRESSID NUMBER,
HOUSENUMBER VARCHAR2(30),
WATERMETER VARCHAR2(30),
ADDDATE DATE,
OWNERTYPEID NUMBER
);

select * from T_OWNERS;
(3).图示

在这里插入图片描述

4).实操

(1)创建工程

在这里插入图片描述

(2)创建数据库连接
package cn.itcast.waterboss.dao;

import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * 基本访问类
 * @param: 获取数据库连接 - 关闭资源
 * @author Ty
 *
 */

public class BaseDao {
	// 1.加载驱动
	static {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	// 2.获取数据库连接
	public static java.sql.Connection getConnection(){
	// thin: 不安装oracle的额外应用 即可连接服务器	
		try {
			return DriverManager.getConnection("jdbc:oracle:thin:@192.168.10.154:1521:orcl", "oracleTest", "123456");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
		
	}
	// 3.关闭资源 : 
	// 参数(结果集 ,执行对象,连接对象)
	
	public static void closeAll(java.sql.ResultSet rs,java.sql.Statement stmt,java.sql.Connection conn) {
		if(rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		if(stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}	
	}	
}

(3)创建实体类
package cn.itcast.waterboss.entity;

import java.util.Date;

/**
 * 实体类
 * @author Ty
 *
 */


public class Owners {
	private Long id;
	private String name;
	private Long addressid;
	private String housenumber;
	private String watermeter;
	private Date adddate;
	private Long ownertypeid;
	
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Long getAddressid() {
		return addressid;
	}
	public void setAddressid(Long addressid) {
		this.addressid = addressid;
	}
	public String getHousenumber() {
		return housenumber;
	}
	public void setHousenumber(String housenumber) {
		this.housenumber = housenumber;
	}
	public String getWatermeter() {
		return watermeter;
	}
	public void setWatermeter(String watermeter) {
		this.watermeter = watermeter;
	}
	public Date getAdddate() {
		return adddate;
	}
	public void setAdddate(Date adddate) {
		this.adddate = adddate;
	}
	public Long getOwnertypeid() {
		return ownertypeid;
	}
	public void setOwnertypeid(Long ownertypeid) {
		this.ownertypeid = ownertypeid;
	}
}

(4)构建增删改方法
package cn.itcast.waterboss.dao;

import java.sql.SQLException;

import cn.itcast.waterboss.entity.Owners;



public class OwnersDao {

	//	增
	public static void add(Owners owners) {
		// 1.初始化执行/连接对象为空
		java.sql.Connection conn = null;
		// 预处理:防止注入攻击
		java.sql.PreparedStatement stmt = null;

		try {
			// 2.获取数据库连接
			conn = BaseDao.getConnection();
			// 3.赋值
			stmt = conn.prepareStatement("insert into T_OWNERS values(?,?,?,?,?,?,?)");
			// 参数索引从1开始
			stmt.setLong(1, owners.getId());
			stmt.setString(2, owners.getName());
			stmt.setLong(3, owners.getAddressid());
			stmt.setString(4, owners.getHousenumber());
			stmt.setString(5, owners.getWatermeter());
			// 日期转换
			stmt.setDate(6, new java.sql.Date(owners.getAdddate().getTime()));
			stmt.setLong(7, owners.getOwnertypeid());
			// 4.语句执行
			stmt.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			// 5.关闭
			BaseDao.closeAll(null, stmt, conn);
		}
	}

	//  改
	public static void update(Owners owners) {

		java.sql.Connection conn = null;
		java.sql.PreparedStatement stmt = null;

		try {
			conn = BaseDao.getConnection();
			stmt = conn.prepareStatement("update T_OWNERS set name=?,addressid=?,housenumber=?,"
					+ "watermeter=?,adddate=?, ownertypeid=? where id=?");
			stmt.setString(1, owners.getName());
			stmt.setLong(2, owners.getAddressid());
			stmt.setString(3, owners.getHousenumber());
			stmt.setString(4, owners.getWatermeter());
			stmt.setDate(5, new java.sql.Date(owners.getAdddate().getTime()));
			stmt.setLong(6, owners.getOwnertypeid());
			// where限制id在最后 
			stmt.setLong(7, owners.getId());
			stmt.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			BaseDao.closeAll(null, stmt, conn);
		}
	}

	//  删
	public static void delete(Long id) {

		java.sql.Connection conn = null;
		java.sql.PreparedStatement stmt = null;

		try {
			conn = BaseDao.getConnection();
			stmt = conn.prepareStatement("delete from T_OWNERS where id=?");
			stmt.setLong(1, id);
			stmt.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			BaseDao.closeAll(null, stmt, conn);
		}
	}
	
}

(5)代码测试
// 增
package cn.itcast.waterboss.test;

import java.util.Date;

import cn.itcast.waterboss.dao.OwnersDao;
import cn.itcast.waterboss.entity.Owners;

public class testAdd {
	public static void main(String[] args) {
		Owners owners = new Owners();
		owners.setId(1L);
		owners.setName("王强");
		owners.setAddressid(1L);
		owners.setHousenumber("2-2");
		owners.setWatermeter("1234");
		owners.setAdddate(new Date());
		owners.setOwnertypeid(1L);
		OwnersDao.add(owners);
	}
}

// 改
package cn.itcast.waterboss.test;

import java.util.Date;

import cn.itcast.waterboss.dao.OwnersDao;
import cn.itcast.waterboss.entity.Owners;

public class testUpdate {
	public static void main(String[] args) {
		Owners owners = new Owners();
		owners.setId(1L);
		owners.setName("王强");
		owners.setAddressid(1L);
		owners.setHousenumber("2-1");
		owners.setWatermeter("1234");
		owners.setAdddate(new Date());
		owners.setOwnertypeid(1L);
		OwnersDao.update(owners);
	}
}

// 删
package cn.itcast.waterboss.test;

import cn.itcast.waterboss.dao.OwnersDao;

public class testDelete {
	public static void main(String[] args) {
		OwnersDao.delete(1L);
	}
}

效果图示
在这里插入图片描述
参考资源

5.伪x

1).伪列

(1).特征
是否存储在表中0
是否可以增删改0
查询1
实例ROWID - ROWNUM
(2).实例
1.ROWID

实质:多了个标识

2.ROWNUM

实质:加序号

运算符(支持):<= ;<
应用:分页查询

2).分页查询

伪列的实际应用

思路:通过子查询

– 1.基本查询(T_ACCOUNT里面:10-20)
– 2.基于排序的分页(降序)
基于排序要在嵌套一层子查询
ROWNUM:在排序前生成(一查询即生成)

-- 1.分页查询(T_ACCOUNT里面:10-20)
SELECT *
FROM (
SELECT ROWNUM r, t.*
FROM T_ACCOUNT t 
)
WHERE r < 20 AND r > 10

-- 2.基于排序的分页

SELECT *
FROM(
SELECT ROWNUM r,t.*
FROM (
SELECT *
FROM T_ACCOUNT t 
ORDER BY USENUM
)t )
WHERE r > 10 AND r < 20

示意图
在这里插入图片描述

3).伪表

不实际存在的表
提供了各种系统和元数据信息
用于查询和管理数据库中的对象和引用

示例内容SQL
DUAL只包含一个列和一行数据SELECT * FROM dual;
USER_TABLES当前用户拥有的所有表的列表SELECT TABLE_NAME FROM USER_TABLES;
USER_TAB_COLUMNS当前用户拥有的所有表中列SELECT COLUMN_NAME, DATA_TYPE, DATA_LENGTH FROM USER_TAB_COLUMNS WHERE TABLE_NAME = ‘MY_TABLE’;

4).

6.函数

Oracle遵循更为严格SQL语法,SELECT后面一定要跟FROM
在函数上也和MySQL有一定差异

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

1).常用函数

在这里插入图片描述字符串截取(MySQL → Oracle)
substring → substr
当前日期
current_date → sysdate

2).日期函数

需求:
1.获取当前时间
2.在当前日期基础上加指定的月
3.求所在月最后一天

select sysdate from dual;
select add_months(sysdate,2) from dual;
select last_day(sysdate) from dual;

3).

7.集合运算

运算关键字
交集INTERSECT
并集UNION
差集MINUS

不去掉重复记录:UNION ALL
MySQL中,MINUS被替换为了EXCEPT

差集实例:
在这里插入图片描述

select * from t_owners where id<=7
minus
select * from t_owners where id>=5;

在这里插入图片描述
*待完善

8.事务(MySQL举例)

/*
 Navicat Premium Data Transfer

 Source Server         : MySQL
 Source Server Type    : MySQL
 Source Server Version : 80032
 Source Host           : localhost:3306
 Source Schema         : ssm

 Target Server Type    : MySQL
 Target Server Version : 80032
 File Encoding         : 65001

 Date: 28/06/2023 17:17:46
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for book
-- ----------------------------
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book`  (
  `id` int NOT NULL,
  `name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '图书名称',
  `number` int NOT NULL COMMENT '馆藏数量',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1019 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '图书表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of book
-- ----------------------------
INSERT INTO `book` VALUES (15, '云计算', 20);
INSERT INTO `book` VALUES (1000, 'Java程序设计', 10);
INSERT INTO `book` VALUES (1001, '数据结构', 10);
INSERT INTO `book` VALUES (1002, '设计模式', 10);
INSERT INTO `book` VALUES (1003, '编译原理', 10);
INSERT INTO `book` VALUES (1005, '操作系统', 11);
INSERT INTO `book` VALUES (1006, '计算机网络', 12);
INSERT INTO `book` VALUES (1007, '计算机网络', 12);
INSERT INTO `book` VALUES (1008, '计算机组成与原理', 12);
INSERT INTO `book` VALUES (1010, '编译原理', 15);
INSERT INTO `book` VALUES (1011, 'Java程序设计', 10);
INSERT INTO `book` VALUES (1012, '数据结构', 10);
INSERT INTO `book` VALUES (1013, '设计模式', 10);
INSERT INTO `book` VALUES (1014, '编译原理', 10);
INSERT INTO `book` VALUES (1015, '操作系统', 11);
INSERT INTO `book` VALUES (1016, '计算机网络', 2);
INSERT INTO `book` VALUES (1017, '计算机网络', 22);
INSERT INTO `book` VALUES (1018, '计算机组成与原理', 12);
INSERT INTO `book` VALUES (1019, '编译原理', 15);

SET FOREIGN_KEY_CHECKS = 1;

需求:
1017向1016借若干本书
分析:
借多少?够不够借?借完后两者如何变化?
思路:
使用事务(三部曲:开启-提交-回滚)实现
核心步骤:
事务开启 - 借书 -
(无异常):提交事务
(有异常):事务回滚

// 核心代码(测试类)
public class BorrowBooks {
    public static void main(String[] args) {
    
        int borrowerId = 1017;
        int lenderId = 1016;
        int borrowAmount = 10;

        // 开启数据库连接
        Connection conn = BookDao.getConnection();

        try {
            // 开启事务
            conn.setAutoCommit(false);

            // 借阅书籍
            borrowBooks(conn, lenderId, borrowerId, borrowAmount);

            // 提交事务
            conn.commit();


        } catch (SQLException e) {
            e.printStackTrace();
            try {
                // 回滚事务
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            // 关闭数据库连接
            BookDao.closeAll(null, null, conn);
        }
    }

    private static void borrowBooks(Connection conn, int lenderId, int borrowerId, int borrowAmount) throws SQLException {
        // 查询借出书籍数量
        String querySql = "SELECT number FROM book WHERE id = ?";
        PreparedStatement queryStmt = conn.prepareStatement(querySql);
        queryStmt.setInt(1, lenderId);
        ResultSet resultSet = queryStmt.executeQuery();

        int availableBooks = 0;
        if (resultSet.next()) {
            availableBooks = resultSet.getInt("number");
        }

        if (availableBooks < borrowAmount) {
            System.out.println("书籍数量不足!剩余 " + availableBooks + " 本书。无法借阅 " + borrowAmount + " 本书。");
            return;
        } else {


            // 扣除借出书籍数量
            String lendSql = "UPDATE book SET number = number - ? WHERE id = ?";
            PreparedStatement lendStmt = conn.prepareStatement(lendSql);
            lendStmt.setInt(1, borrowAmount);
            lendStmt.setInt(2, lenderId);
            lendStmt.executeUpdate();

            // 增加借入书籍数量
            String borrowSql = "UPDATE book SET number = number + ? WHERE id = ?";
            PreparedStatement borrowStmt = conn.prepareStatement(borrowSql);
            borrowStmt.setInt(1, borrowAmount);
            borrowStmt.setInt(2, borrowerId);
            borrowStmt.executeUpdate();

            // 关闭语句
            lendStmt.close();
            borrowStmt.close();
            System.out.println("成功借阅书籍!");
        }
    }
}

// BaseDao(工具类)
public class BookDao {
    
    static {
        try {
           Class.forName("com.mysql.cj.jdbc.Driver");

        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    // 2.获取数据库连接

    public static java.sql.Connection getConnection(){
        try {
            return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/ssm", "root", "123456");
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;

    }

    // 3.关闭资源 :
    // 参数(结果集 ,执行对象,连接对象)

    public static void closeAll(java.sql.ResultSet rs,java.sql.Statement stmt,java.sql.Connection conn) {
        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
        if(stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if(conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}
// 实体类
@TableName("book")
@Data
public class Book {
    @TableId(type = IdType.AUTO)
    private int id;
    @TableField("name")
    private String name;
    @TableField("number")
    private int number;

    public Book(int id, String name, int number) {
        this.id = id;
        this.name = name;
        this.number = number;
    }

    public Book() {

    }
}

代码结构:
在这里插入图片描述思考:
为什么上述的业务需求中要使用事务?
如果不使用事务(三部曲)可能会发生什么情况?

事务的特性
思考上面的问题需要了解一下事务的特性
首先事务具有一致性-隔离性
事务前后的数据,保持业务上的一致;
事务进行,其他事务受限;

即当a在借书操作的业务未完成时,b借书的业务无法被响应,
且a在借书前后可通过事务命令来保证数据前后的一致性。

如果不使用事务即数据的一致性难以被保持。
两种操作:
更新借出方的书籍数量和更新借入方的书籍数量。
如果其中一个操作成功,而另一个操作失败(如网络中断、系统崩溃等),会导致数据不一致的情况,例如借出方书籍减少了,但借入方的书籍数量未增加

9.多表练习

1.建表语句

CREATE TABLE student(
Sid VARCHAR2(10) PRIMARY KEY,
Sname NVARCHAR2(10) NOT NULL,
Ssex NVARCHAR2(10) NOT NULL,
Sbirthday DATE,
Sclass VARCHAR2(5)
);

INSERT INTO student VALUES('108', '曾华', '男', TO_DATE('1977-09-01', 'YYYY-MM-DD'), '95033');
INSERT INTO student VALUES('110', '张三', '男', TO_DATE('1977-09-01', 'YYYY-MM-DD'), '95032');
INSERT INTO student VALUES('105', '匡明', '男', TO_DATE('1975-10-02', 'YYYY-MM-DD'), '95031');
INSERT INTO student VALUES('107', '王丽', '女', TO_DATE('1976-01-23', 'YYYY-MM-DD'), '95033');
INSERT INTO student VALUES('101', '李军', '男', TO_DATE('1976-02-20', 'YYYY-MM-DD'), '95033');
INSERT INTO student VALUES('109', '王芳', '女', TO_DATE('1975-02-10', 'YYYY-MM-DD'), '95031');
INSERT INTO student VALUES('103', '陆君', '男', TO_DATE('1974-06-03', 'YYYY-MM-DD'), '95031');

CREATE TABLE course(
Cid VARCHAR2(10) PRIMARY KEY,
Cname NVARCHAR2(10) NOT NULL,
Tid VARCHAR2(10) NOT NULL
);

INSERT INTO course VALUES('3-105', '计算机导论', '825');
INSERT INTO course VALUES('3-245', '操作系统', '804');
INSERT INTO course VALUES('6-166', '数据电路', '856');
INSERT INTO course VALUES('9-888', '高等数学', '831');

CREATE TABLE teacher(
Tid VARCHAR2(10) PRIMARY KEY,
Tname VARCHAR2(10),
Tsex VARCHAR2(10),
Sbirthday DATE,
Prof VARCHAR2(10),
Depart VARCHAR2(10)
);

INSERT INTO teacher VALUES('804', '李诚', '男', TO_DATE('1958-12-02', 'YYYY-MM-DD'), '副教授', '计算机系');
INSERT INTO teacher VALUES('856', '张旭', '男', TO_DATE('1969-03-12', 'YYYY-MM-DD'), '讲师', '电子工程系');
INSERT INTO teacher VALUES('825', '王萍', '女', TO_DATE('1972-05-05', 'YYYY-MM-DD'), '助教', '计算机系');
INSERT INTO teacher VALUES('831', '刘冰', '女', TO_DATE('1977-08-14', 'YYYY-MM-DD'), '助教', '电子工程系');

CREATE TABLE sc(
Sid VARCHAR2(10),
Cid VARCHAR2(10),
score NUMBER(3, 1),
CONSTRAINT pk_sc_test3 PRIMARY KEY (Sid, Cid),
FOREIGN KEY (Cid) REFERENCES course(Cid),
FOREIGN KEY (Sid) REFERENCES student(Sid)
);

INSERT INTO sc VALUES('103', '3-245', 86);
INSERT INTO sc VALUES('105', '3-245', 75);
INSERT INTO sc VALUES('109', '3-245', 68);
INSERT INTO sc VALUES('103', '3-105', 92);
INSERT INTO sc VALUES('105', '3-105', 88);
INSERT INTO sc VALUES('109', '3-105', 76);
INSERT INTO sc VALUES('101', '3-105', 64);
INSERT INTO sc VALUES('107', '3-105', 91);
INSERT INTO sc VALUES('108', '3-105', 78);
INSERT INTO sc VALUES('101', '6-166', 85);
INSERT INTO sc VALUES('107', '6-166', 79);
INSERT INTO sc VALUES('108', '6-166', 81);


图示:
在这里插入图片描述

2.需求

-- 1.查询没学过"张三"老师讲授的任一门课程的学生姓名

-- 2、查询选修“3-105”课程的成绩高于“109”号同学成绩的所有同学的记录

-- 3、查询和学号为108的同学同年出生的所有学生的Sid、Sname和Sbirthday列

-- 4、查询选修某课程的同学人数多于5人的教师名

-- 5、查询成绩比该课程平均成绩低的同学的成绩表

-- 6、查询至少有2名男生的班号

-- 7.查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩

-- 8.按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩

-- 9. 查询没有学全所有课程的同学的信息

3.实现

-- 4、查询选修某课程的同学人数多于5人的教师名

-- 思路
-- 1)先查询'选修某课程的同学人数多于5人'
-- 2)分析:某课程的同学人数由'cid'决定
-- 3)			要对聚合后某列进行操作:Having聚合筛选	
-- 4)最终结果:'Tname',而'cid'位于'sc' 和 'course'表中
-- 5)分析:从	'cid'关联'Tname' → 子查询/外连接
-- 6)		  'course'表的'cid'无法获取到'选修某课程的同学人数'
--          (由表结构和插入数据分析)
-- 7)       故只能由'sc'表关联'teacher'表,而'course'表的'Tid'刚好可以作为媒介

SELECT Tname 
FROM 
(SELECT cid FROM sc GROUP BY cid HAVING COUNT(*) > 5)sc,
COURSE co,TEACHER te 
WHERE co.CID = sc.CID
AND te.TID = co.tid

-- 5、查询成绩比该课程平均成绩低的同学的成绩表

-- WHERE sc1.cid = sc2.cid :确保是同一门课的成绩进行比较
-- ROUND(AVG(score), 1):保留小数点后1位

SELECT *
FROM(SELECT sid,cid,score FROM sc)sc1,
(SELECT cid,ROUND(AVG(score), 1) avg_score FROM sc GROUP BY cid)sc2
WHERE sc1.cid = sc2.cid 
AND sc1.score < sc2.avg_score

-- 6、查询至少有2名男生的班号

SELECT ssex,sclass,COUNT(*) count_sclass
FROM STUDENT
GROUP BY ssex,sclass
HAVING COUNT(*) >=2 
AND ssex = '男'

-- 7.查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩

SELECT sc1.avg_score, st.sid, st.sname
FROM
(SELECT sid,AVG(score) avg_score 
FROM sc 
GROUP BY sid 
HAVING AVG(score) >= 60)sc1
LEFT JOIN STUDENT st 
ON sc1.sid = st.sid 

-- 8.按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩

-- 子查询
SELECT sc1.avg_score, sc2.score
FROM(
SELECT sid,AVG(score) avg_score 
FROM sc 
GROUP BY sid) sc1,
(SELECT sid,score FROM sc) sc2 
WHERE sc1.sid = sc2.sid 
ORDER BY sc1.avg_score DESC, sc2.score DESC
-- 外连接
SELECT sc.sid, sc.score, avg_score.avg_score
FROM sc
INNER JOIN (
  SELECT sid, AVG(score) avg_score 
  FROM sc 
  GROUP BY sid
) avg_score ON sc.sid = avg_score.sid
ORDER BY avg_score.avg_score DESC;

-- 9. 查询没有学全所有课程的同学的信息

SELECT st.SID, st.SNAME,st.SSEX,st.SBIRTHDAY,st.SCLASS
FROM student st, sc
WHERE st.Sid = sc.Sid
GROUP BY st.SID, st.SNAME,st.SSEX,st.SBIRTHDAY,st.SCLASS
HAVING COUNT(sc.Cid) < (SELECT COUNT(*) FROM course);

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

似云似月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值