数据库系统概念笔记——第五章:高级SQL

第五章:高级SQL

5.1 使用程序设计语言访问数据库

可以使用以下两种方法通过编程语言访问SQL

  • 动态SQL:动态SQL允许运行时以字符串形式构建SQL,提交查询和更新
  • 嵌入式SQL:嵌入式SQL必须在编译时全部确定,并交给预处理器

动态SQL中分为JDBC和ODBC
JDBC:Java语言开发的应用接口
ODBC:C语言,C++,C#等

5.1.1 JDBC

JDBC连接MySQL数据库的例子

public static boolean loginSuccess(String name,String password) 
{
	//连接数据库
	Connection coon = null;
	Statement stmt = null;
	ResultSet rs = null;
	try 
	{
		//注册驱动
		DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
		//获取连接
		coon = DriverManager.getConnection("jdbc:mysql://localhost:3306/database_name?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true","root","123");
		//获取数据库操作对象
		stmt = coon.createStatement();
		//执行sql语句,从login表中查找数据
		String selectSql = "select * from login";
		rs = stmt.executeQuery(selectSql);
		//处理查询结果集
		while(rs.next()) 
		{
			//如果账号密码相同并且没有登录时,就返回真
			if(name.equals(rs.getString("name")) && password.equals(rs.getString("password")) && rs.getInt("isonline") == 0) 
			{
				return true;
			}
		}
	}
	catch(Exception e) 
	{
		e.printStackTrace();
	}
	finally 
	{
		//释放资源
		if(rs != null) 
		{
			try 
			{
				rs.close();
			}
			catch(Exception e) 
			{
				e.printStackTrace();
			}
		}
		if(stmt != null) 
		{
			try 
			{
				stmt.close();
			}
			catch(Exception e) 
			{
				e.printStackTrace();
			}
		}
		if(coon != null) 
		{
			try 
			{
				coon.close();
			}
			catch(Exception e) 
			{
				e.printStackTrace();
			}
		}
	}
	return false;
}

预备语句

可以用"?"代表以后给出的实际值
在这里插入图片描述
可以使用PreparedStatement,提高应用程序的安全性,防止SQL注入

SQL注入

假设下面的查询

"select * from instructor where name = '" + name + "'"

如果用户不是输入名字,而是输入:'X' or 'Y' = Y'
那么where子句始终为真,则会返回整张instructor表,这会导致信息泄露

使用预备语句可以解决这类问题,因为输入的字符串将被插入转义字符
变为:

"select * from instructor where name = 'X\ ' or \ 'Y\ ' = \ 'Y'"

返回的结果为空集

元数据

1.ResultSetMetaData对象

当执行完一个executeQuery方法后,查询的结果被封装在ResultSet数据集中
ResultSet接口有一个getMataData()方法,返回包含结果集元数据的ResultSetMetaData对象

ResultSetMetaData rsmd = rs.getMetaData();
for(int i = 1; i <= rsmd.getColumnCount(); i++) 
{         
   System.out.println(rsmd.getColumnName(i));              
   System.out.println(rsmd.getColumnTypeName(i));
}

getColumnCount()方法返回结果关系的属性个数
对于每一个属性,可以使用getColumnName()和getColumnTypeName()方法分别得到名称和数据类型

2.DatabaseMetadata接口

Connection接口通过getMetadata()方法用于返回一个DatabaseMetadata对象
DatabaseMetadata接口有大量的方法可以用于获取程序所连接的数据库和数据库系统的元数据

DatabaseMetadata dbmd = coon.getMetadata();
//getColumns参数:类别,模式名,表名,列名
//返回值:每列包含一行COLUMN_NAME,TYPE_NAME
ResultSet rs = dbmd.getColumns(null,"univdb","department","%");
while(rs.next())
{
	System.out.println(rs.getString("COLUMN_NAME"),rs.getString("TYPE_NAME"));
}

JDBC中的事务控制

在默认情况下,每个SQL语句都被作为一个被自动提交的独立的事务
对于有多个更新的事务,这种做法并不好,因此建议将自动提交关闭

conn.setAutoCommit(false);

事务必须被显式的提交或回滚

conn.commit();
conn.rollback();

可以使用conn.setAutoCommit(true) 打开自动提交

5.1.3 嵌入式SQL

SQL标准定义了嵌入SQL到许多不同的语言中,例如C,C++,Java等。SQL查询所嵌入的语言被称为宿主语言,宿主语言中使用的SQL结构被称为嵌入式SQL

使用宿主语言写出的程序可以通过嵌入式SQL的语法访问和修改数据库中的数据

在JDBC中,SQL语句是在运行时被解释的,但是在嵌入式SQL中,一些SQL相关的错误可以在编译过程中被发现

使用EXEC SQL语句,让预处理器识别嵌入式SQL请求

EXEC SQL <嵌入式SQL语句>

连接数据库

EXEC SQL connect to server user user-name using password

server:将要连接的服务器

嵌入式SQL语句中可以使用宿主语言的变量

前面要加上“:”以区别于SQL变量

EXEC SQL BEGIN DECLARE SECTION:
int a;
EXEC SQL END DECLARE SECTION:

为了表示关系查询,使用声明游标语句

宿主变量为a

EXEC SQL
	declare c cursor for
	select id,name
	from student
	where tot_cred > :a;

上述表达式中的变量c称为该查询的游标,可以用c来标识该查询,然后用open语句执行该查询

EXEC SQL open c;

利用游标更新数据库关系

EXEC SQL
	declare c cursor for
	select *
	from instructor
	where dept_name = 'Music'
	for update;
EXEC SQL
	update instructor
	set salary = salary + 100
	where current of c;

5.2 函数和过程

SQL允许定义函数,过程和方法
这里介绍的是SQL标准所定义的语法

5.2.1 声明和调用SQL函数和过程

定义一个函数,函数的功能是:给定一个系的名字,返回该系的教师数目

create function dept_count(dept_name varchar(20))
	returns integer
	begin
	declare d_count integer;
		select count(*) into d_count
		from instructor
		where instructor.dept_name = dept_name
	return d_count;
	end

使用该函数进行查询

select dept_name,budget
from department
where dept_count(dept_name) > 12;

SQL标准支持返回关系作为结果的函数,这种函数称为表函数

create function teacher_of (dno char(20)
	returns table (tno varchar(5),
		name varchar(20),
		salary numeric(8,2))
return table
		(select  tno, tname, salary
	     from t
	     where t.dno = teacher_of.dno)

使用

select *
from table (teacher_of (‘d01’))
5.2.2 支持过程和函数的语言构造

SQL1999支持for循环,允许对查询的所有结果重复执行

declare n integer default 0:
for r as
		select budget from department
		where dept_name = 'Music'
do
	set n = n - r.budget
end for

其它部分略去

5.3 触发器

触发器是一条语句,当对数据库作修改时,它被系统自动执行
设置触发器机制,需要满足两个要求

  • 指明什么条件下执行触发器
  • 指明触发器执行时的动作

设置职工工资涨幅不能超过10%

create trigger RAISE_LIMIT 
after update of sal on EMP
	referencing new row as nrow old row as orow
	for each row
	when (nrow.sal > 1.1 * orow.sal)
		begin
			signal SQLSTATE '7500' (Salary increase 10%)
		end	

5.4 递归查询

语法格式

select * from. where  [结果过滤条件语句]
start with  [and起始条件过滤语句]
connect by prior [and中间记录过滤条件语句]

select * 
from p
start with parent='a' connect by prior child=parent; 

结果集
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值