大概一年前的这个时候,为了深入了解数据库的内部原理和实现,我决定编写一个数据库系统的原型程序,这个行动断断续续坚持了一年,写了接近3W行C代码,现在除了事务和并发(只做到了存储引擎层面的并发),其他的功能基本都实现了。数据库是底层软件,实现起来有一定难度,为了编写这个程序(暂且就叫做XSQL吧),我阅读了很多关于开源数据库内部原理的书籍资料,总结了主流数据库的结构,然后依据其原理写出了XSQL。接下来我打算把实现这个程序中遇到的问题,解决的办法和涉及的技术写成一个专题,这样可以让更多同学更加深入的理解数据库系统的内部原理,还可以让他人发现我实现过程中的不足之处,指出优化方法。


XSQL中的数据类型(绿色暂未实现):

CHAR

定长字符串

VARCHAR

变长字符串

FLOAT

单精度浮点型

DOUBLE

双精度浮点型

INT

整型

SMALLINT

短整型

BIGINT

长整型

DATETIME

时间戳

TEXT

文本

FILE

文件

 

XSQL支持的函数:

字符串函数

LENGTH(exp)

返回字符串exp的长度

SUBSTR(exp1,exp2)

返回串exp2在exp1中出现的下标,如果不存在则返回-1

时间函数

GETDATE()

返回当前的系统时间字符串

TODATE(exp)

将时间戳exp转化为时间字符串

TOTIMESTAMP(exp)

将时间字符串exp转化为时间戳

数学函数

POWER(exp1,exp2)

返回exp1的exp2次幂

SIN(exp)

返回exp的正弦值

COS(exp)

返回exp的余弦值

SQRT(exp)

返回exp的平方根

ABS(exp)

返回exp的绝对值

聚合函数

MAX(exp)

返回最大的exp

MIN(exp)

返回最小的exp

SUM(exp)

返回所有行的exp的和

COUNT(exp)

返回行数

AVG(exp)

返回所有行的exp平均值

 

在XSQL中执行如下命令建立学生选课关系表:

CREATE TABLE student
 (
  s# INT AUTO_INCREMENT NOT NULL ,
  name CHAR(20) ,
  age SMALLINT CHECK(age  BETWEEN 15 AND 20) ,
  sex CHAR(2) CHECK(sex IN('男','女')) ,
  address VARCHAR(50) ,
  reg_time DATETIME ,
  PRIMARY KEY(s#)
 )INSERT INTO student(s#,name,age,sex ,address ,reg_time)
 VALUES (NULL,'wang',20,'男','哈尔滨',totimestamp(getdate()))INSERT INTO student(s#,name,age,sex ,address ,reg_time)
 VALUES (NULL,'li',19,'男','哈尔滨',totimestamp(getdate()))INSERT INTO student(s#,name,age,sex ,address ,reg_time)
 VALUES (NULL,'chen',17,'男','哈尔滨',totimestamp(getdate()))INSERT INTO student(s#,name,age,sex ,address ,reg_time)
 VALUES (NULL,'wu',18,'男','哈尔滨',totimestamp(getdate()))INSERT INTO student(s#,name,age,sex ,address ,reg_time)
 VALUES (NULL,'luo',20,'女','哈尔滨',totimestamp(getdate()))INSERT INTO student(s#,name,age,sex ,address ,reg_time)
 VALUES (NULL,'zhou',20,'女','哈尔滨',totimestamp(getdate()))CREATE TABLE course
 (
  c# INT AUTO_INCREMENT NOT NULL,
  cname CHAR(15),
  teacher CHAR(15),
  PRIMARY KEY(c#)
 )INSERT INTO course(c#,cname,teacher) VALUES(NULL,'数据库','li') 
 INSERT INTO course(c#,cname,teacher) values(NULL,'数学','ma') 
 INSERT INTO course(c#,cname,teacher) values(NULL,'化学','zhou') 
 INSERT INTO course(c#,cname,teacher) values(NULL,'物理','shi') 
 INSERT INTO course(c#,cname,teacher) values(NULL,'操作系统','wen')CREATE TABLE sc
 (
  s# INT  NOT NULL,
  c# INT  NOT NULL,
  grade SMALLINT CHECK(grade BETWEEN 0 AND 100),
  PRIMARY KEY(s#,c#),
  FOREIGN KEY(s#) REFERENCES student(s#),
  FOREIGN KEY(c#) REFERENCES course(c#)
 )INSERT INTO sc(s#,c#,grade) values(1,1,55)
 INSERT INTO sc(s#,c#,grade) values(1,2,78)
 INSERT INTO sc(s#,c#,grade) values(1,3,85)
 INSERT INTO sc(s#,c#,grade) values(1,4,91)
 INSERT INTO sc(s#,c#,grade) values(1,5,69)
 INSERT INTO sc(s#,c#,grade) values(2,1,85)
 INSERT INTO sc(s#,c#,grade) values(3,1,90)
 INSERT INTO sc(s#,c#,grade) values(3,2,86)
 INSERT INTO sc(s#,c#,grade) values(3,3,95)
 INSERT INTO sc(s#,c#,grade) values(4,1,71)
 INSERT INTO sc(s#,c#,grade) values(4,4,63)
 INSERT INTO sc(s#,c#,grade) values(5,1,70)
 INSERT INTO sc(s#,c#,grade) values(5,2,65)
 INSERT INTO sc(s#,c#,grade) values(5,3,80)
 INSERT INTO sc(s#,c#,grade) values(5,5,65)
 INSERT INTO sc(s#,c#,grade) values(6,1,78)
 INSERT INTO sc(s#,c#,grade) values(6,3,90)

查询演示:



--列出student表的所有行

SELECT s#,name ,age ,sex ,address ,todate(reg_time)
FROM student

设置只使用一个数据库连接java 实现一个数据库_数据库

 

--列出course表的所有行

SELECT*
FROM course

设置只使用一个数据库连接java 实现一个数据库_字符串_02

 

--检索学习课程号为2的学生学号与姓名

SELECT s#,name
FROM student
WHERE EXISTS (
         SELECT *
         FROM sc
         WHERE c#=2 AND s#=student.s#
         )

设置只使用一个数据库连接java 实现一个数据库_数据库_03

 

--检索学习数学的学生学号,姓名和入学时间

SELECT name,student.s# ,todate(reg_time) as '入学时间'
FROM student,sc,course
WHERE cname='数学' AND student.s#=sc.s# AND sc.c#=course.c#

设置只使用一个数据库连接java 实现一个数据库_字符串_04

 

--检索学习全部课程的学生姓名

SELECT name
FROM student
WHERE NOT EXISTS(
              SELECT *
              FROM course
              WHERE NOT EXISTS(
                            SELECT *
                            FROM sc
                            WHERE s#=student.s# ANDc#=course.c#
                            )
              )

设置只使用一个数据库连接java 实现一个数据库_数据库_05

 

--检索名字小于等于平均长度的学生信息

SELECT *
FROM student
WHERE LENGTH(name) <= (SELECT AVG(LENGTH(name)) FROM student)

设置只使用一个数据库连接java 实现一个数据库_数据库_06

 

--检索大于等于平均年龄且最高分数和最低分数之差不超过10分或者小于平均年龄且之差不超过15的学生信息

SELECT *
FROM student
WHERE 
(
10 > (SELECT MAX(grade) - MIN(grade)
      FROM SC
      WHERE s# =student.s#) AND age >= (SELECT AVG(age) FROM student)
) OR (
15 > (SELECT MAX(grade) - MIN(grade)
      FROM SC
      WHERE s# =student.s#) AND age < (SELECT AVG(age) FROM student)
)

设置只使用一个数据库连接java 实现一个数据库_设置只使用一个数据库连接java_07