本文是2016年的学习笔记,最近工作用到了SQL,顺手调整了下格式分享出来。
结构化查询语言SQL(structured query language),是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系型数据库,遵循ANSI SQL标准。结构化查询语言sql是高级的非过程化的编程语言,允许用户在高层数据结构工作。不要求用户指定对数据的存放方法,也不要求用户了解具体的数据存放方式,所以具有完全不同底层结构的数据库系统可以使用相同的sql作为数据输入和管理的接口。
SQL语言的4个部分:
大多数数据库表的字段都指定了相关的数据类型,相当于Java语言编程中变量的数据类型。SQLite采用动态数据类型,可以对字段不指定任何数据类型,SQLite会根据存入值自动判断。
sqlite的5种常用数据类型
NULL
空值,相当于Java中的null;INTEGER
带符号的整型,相当于Java中的int;REAL
浮点数字,相当于Java中的float/double型;TEXT/VARCHAR
字符串,相当于Java中的string类,一个字符2个字节。text很长(比如文章),varchar比如姓名等字段,char(10)不能超过指定的长度;BLOB
二进制对象,相当于Java中的byte数组,用于存储声音、视频、图片等;mysql的常用数据类型
CREATE TABLE
创建表时,应该将每个字段的约束条件进行说明,以后往表里输入数据的时候,系统会自动检查是否满足约束条件,如不满足会报错。主要有以下5种约束:
约束 | 关键词 | 示例 |
---|---|---|
条件检查 | CHECK(condition) | 年龄–至少大于20岁小于80:age int check(age >20 and age<80) |
默认 | DEFAULT (XXX) | 国籍–默认中国:nationality varchar(10) default(‘china’) |
非空 | NOT NULL | 姓名—不能为空:name varchar(10) not null |
主键 | PRIMARY KEY | 员工号—主键:id int primary key autoincrement |
外键 | FOREIGN KEY | 员工饭卡号—根据员工号得来:card_id int references workers.id |
唯一 | unique | - |
自增列 | mysql:auto_increment sqlite:autoincrement |
- |
注意:
- sqlite主键的类型要用integer,不然不会自增长,
- MySQL必须显示声明auto-increment才能自增长;主键不一定是整型,可以是任意的数据类型;
# 创建数据库,命令:sqlite3
sqlite3 stu.db
安卓不用管数据库的创建,sqliteOpenHelper对象new出来时就自动创建了
# 创建
create database <db_name>
# 删除
drop database <db_name>
# 打开数据库
use <db_name>
# 输出列头
.header on
# 列表显示
.mode column
# 以列的形式显示
.mode line
.database
# 查看所有表
.table
# 查看当前数据库指定表
.tables <table_name>
# 查看所有表结构及索引信息
select * from sqlite_master
# 查看所有表结构信息
select * from sqlite_master where type = "table"
# 查看所有表名
select name from sqlite_master where type = "table"
# 查看指定表结构
select * from sqlite_master where type = "table" and name = ""
# 查看所有表索引信息
select * from sqlite_master where type = "index"
# 查看指定表索引信息
select * from sqlite_master where tyoe = "index" and name = ""
pragma table_info('' )
desc <table_name>
代码获取:
openHelper.writableDatabase.query("pragma table_info(`$table`)").use {
while (it.moveToNext()) {
it.columnNames.forEach {col->
val index = it.getColumnIndex(col)
if (index != -1) {
Log.d("test", "[$table] - $col: ${it.getString(index)}")
}
}
}
}
-sqlite:
# 所有表的建表语句
.schema
# 查看指定数据表的建表语句
.schema requires
show create table tableName \G
select count(*) from requires
create table [if not exists] tableName(
col1 type1 [not null] [primary key],
col2 type2 [not null],
...
)
SQLite 中的表和列名称不区分大小写
示例 :创建一个表,字段如下:
字段名 | 类型 | 约束 | 说明 |
---|---|---|---|
id | integer | 主键,自增长 | 编号 |
name | varchar | 长度20,非空 | 姓名 |
cid | integer | - | 所在班级 |
age | integer | 大于10且小于60 | 年龄 |
gender | bit | 默认1,表示男 | 性别 |
score | real | - | 成绩 |
相应的语句为:分号表示一条语句结束
create table student(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(20) NOT NULL,
cid INTEGER,
age INTEGER CHECK(age>18 and age<60),
gender BIT DEFAULT(1),
score REAL);
alter table tableName add 字段名 字段类型(此处不能加约束)
# 连续添加:
alter table 表名
add 字段1 字段类型 限制,
add 字段2 字段类型 限制;
# 直接添加:
alter table 表名 add(
字段1 字段类型 限制,
字段2 字段类型 限制
);
# 括号内可不输引号
select typeof('' ) from <table_name>
alter table tableName modify 字段名 字段类型
alter table tableName drop 字段名
alter table tableName rename to 新表名
alter table tableName change 旧字段名 新字段名 字段类型
约束名规范:约束简称+表明+字段名
# 主键约束:
alter table tableName add constraint 约束名 primary key (字段名);
# 外键约束:
alter table tableName add constraint 约束名 foreign key (字段名) references 表名(字段名)
# 检查约束:
alter table tableName add constraint 约束名 check(表达式)
# 默认约束
alter table tableName alter 字段名 set default 值
# 自增列约束
alter table tableName modify column 字段名 类型 其他约束 auto_increment
# 所有字段插入数据:
insert [into] tableName values(v1,v2…)
# 为部分字段插入数据:
insert [into] 表名(字段1,字段2,字段3...) values(值1,值2,值3...)
insert into student(name, cid, gender, age, score)values(‘宋江’,1,1,45,46.5);
insert into tableName(field1,field2…) values(value1,value2…), (value1,value2…), (value1,value2…)…
insert into 表名(a,b,c,...) select a1,b1,c1,... from 表名
上面的语句要求两张表都已存在,还有一种要求新表不存在,会自动创建新表:
select a,b insert into table_not_exist from table_name
replace into 表名(字段1,字段2,字段3...) values(值1,值2,值3...)
在使用replace的时候,处理唯一值的时候,先去表中找这个值存不存在,如果不存在插入数据,如果存在,先删除原来的数据,再插入自己的数据。
注意:
- MySQL可以一次插入多条数据,sqlite不行;
- 由于主键id已经设为autoincrement,因此不必手动赋值;
- 数据值涉及到字符串和日期需要使用单引号;
语法:
update 表名 set 字段1 = 新值, 字段2= 新值where 条件
# 新值与旧值相关:
update tableName set 字段1=f(字段1) where 条件
示例:
# 将学生中姓名叫“小明”的改为“小刚”
update student set name=’小刚’ where name=’小明’;
注意 :
- MySQL和sqlite都可以一次更新多个字段;
- 不加Where条件是全部更新;
drop table [if exists] tableName1, tableName2…
alter table 从表名 drop foreign key 外键字段名;
drop table 从表名 主表名;
truncate table tableName;
# 会把整个表数据都删掉
delete from 表名
# 删除符合条件的记录
delete from 表名 where 列名="value"
示例
# 删除成绩低于60分的学生信息:
delete from students where score<60;
# 查询全部:
select * from tableName
# 通用格式
select col1,col2,...
from table1,table2,...
[where <condition>]
[group by <group_by_list>]
[having <condition>]
[order by <order_list> [asc|desc]]
Select语句的执行顺序:
这种执行顺序操作的数据量最小,效率最高。
查询的字段(所有/某个/某些):
# 单个字段:
select id from student where age=18
# 多个字段:
select id, name, score from student
# 所有字段:
select * from student
select * from students where age>18;
select * from students where age>18 and gender=1 and score>60.0;
# 值在某个区间内
select * from students where age between 10 and 20;
# 列举条件:值是某几个数
select * from students where age in(11,13);
# 排除条件:值不是某几个数
select * from students where age notin(11,13)
select * from students where name like ‘%mike%’
select distinct 字段名 from 表名
select distinct * from students where age>18
select * from students where age>18 limit 5
查询结果的统计值:
# 结果的数量:
select count(*) from students where age>18;
# 结果的平均值
select avg(age) from students where gender=1;
# 结果的总和
select sum(age) from students where gender=1;
# 结果的最大值
select max(score) from students where gender=0;
# 结果的最小值
select min(score) from students where gender=1;
查询结果按某个字段分组,分组+聚合函数配合使用可以非常灵活对结果进行查询分析。
# 查询每个专业各有多少学生
select major as ‘专业’,count(*) as ‘人数’ from students group by major;
# 根据不同的年龄、性别统计人数
select age,gender,count(*) from students group by age, gender;
查询分数高于80分的学生姓名、平均分
select sid,name,avg(score) from students group by sid having avg(score)>80
按某个字段降序/升序
# 分数从高到低排序:
select * from students order by score desc;
年龄从小到大排序:
select * from students order by age asc;
按学号和年龄排序:
select * from students order by id,age;
语法:从表字段 references 主表(字段) 约束;
例如:c_id integer references students(s_id) not null;
表格可以分为两种:
连接的两张表地位平等,多张表的数据只有一一对应才会连接。
示例:查询选修了数据库课程的学号、成绩:
select s_id, grade
from course, score
where course.c_id = score.c_id and c_name = ‘数据库’
示例:
select students.s_id, student.s_name, score.c_id, grade from students
inner join score
on student.s_id = score.s_id
两张表的地位不平等,其中基础表的每条数据必须出现,即使另一张表中没有与之匹配的数据也要用null补齐。
格式:
select col_list from table1 left|right [outer] join table2 on table1.col=table2.col;
示例:查询所有学生的生物成绩(有些人没选这门课)
Select s_name as ‘学生姓名’, course as ‘课程’,score as ‘成绩’ from students s
Left outter join scores s on s.s_id=c.s_id
And outter join courses c on c.c_id=s.c_id
And c.c_name=’生物’
把一个查询结果作为另一个查询的条件.
示例:查询选修了1号课程的学生编号和姓名
select s_id,s_name from students
s_id in(select s_id from courses where c_id=1)
使用exists关键字的子查询:子查询有结果外查询才能执行
示例:如何存在姓名为“老张”的学生,则查询其成绩
Select * from scores
Where exists (select * from students where s_name=’老张’);
1)可以把多次查询结果纵向排列;
2)有all关键字才可以显式重复数据;
3)列的数量和类型都要兼容;
示例:查询男生的信息或年龄大于20的学生信息
select * from students where gender=’male’
union [all] -->将信息合并,如果不行合并可以加all
select * from students where age>20
union [all]
select …
SELECT user_qq,gno,score FROM scores
WHERE user_qq='12301'
UNION ALL
SELECT '总分',' ',SUM(score) FROM scores
WHERE user_qq='12301'
sqlite中如果你的数据库设计发生变更,会触发数据库onMigrate或者onUpdate之类的回调,需要开发者给出相应的处理。总结了三种处理策略及其使用场景。
首先数据库变更可以分为两种:
不兼容变更包括:
兼容变更包括:
三种处理策略及其实现代码如下:
database.execSQL("drop table if exists table_name")
database.execSQL("delete from table_name")
database.execSQL("delete from sqlite_sequence where name = table_name")
database.execSQL("CREATE TABLE IF NOT EXISTS `new_table_name` (`col1` INTEGER PRIMARY KEY AUTOINCREMENT, `col2` TEXT NOT NULL, `col3` VARCHAR 20))
database.execSQL("INSERT INTO new_table_name (col1,col2,col3) SELECT col1,col2,col3 FROM table_name");
database.execSQL("DROP TABLE table_name")
database.execSQL("ALTER TABLE new_table_name RENAME TO table_name")
// 新增字段
database.execSQL("ALTER TABLE table_name ADD COLUMN col INTEGER")
// 修改字段约束
database.execSQL("ALTER TABLE table_name MODIFY col INTEGER NOT NULL)
Sqlite是一款轻型轻量级、关系型DBMS,设计目标是嵌入式环境;Sqlite占用资源非常低,在嵌入式设备中可能只需要几百K的内存;比起MySQL、postgreSQL这两款开源DBMS,它的处理速度更快;支持windows/Linux/UNIX等主流操作系统,同时能跟很多多线程语言相结合,如Tcl、C#、PHP、Java等
下载:SQLite第一个alpha版本诞生于2000年,较新的的版本是SQLite3官网:http://www.sqlite.org
安装:sqlite无需安装,下载解压后将sqlite3.exe文件放在D盘下即可使用:
进入命令控制台,输入命令创建一个数据库文件text.db(文件数据库,一个db文件即一个数据库),并退出。
常用工具软件
这些工具已经内置sqlite3数据库,无需再进行数据库连接配置,可直接使用;
以Sqlite developer为例:
sqlite官网中说明了sqlite数据库目前存在的限制条件,相关C库也有限制,我们也可以通过命令行获取相关限制:
# 打开sqlite
sqlite
# 获取限制信息
.limits
内容如下:来源sqlite中的限制
length 1000000000 // 字符串或BLOB的最大长度10亿,一行的最大长度
sql_length 1000000000 // sql语句最大长度
column 2000 // 列数,可以在编译时才可以将最大列出改为32767
expr_depth 1000 // 表达式树的最大深度,SQLite将表达式解析到树中进行处理。
compound_select 500 // 复合SELECT语句中的最大术语数
vdbe_op 25000 // 虚拟机程序中用于实现SQL语句的最大指令数
function_arg 127 // 一个函数的最大参数个数
attached 10 // ATTACH语句,附加数据库最大值为125
like_pattern_length 50000 // LIKE模式匹配算法或GLOB模式的最大长度
variable_number 250000 // 任何参数的索引号
trigger_depth 1000 // 触发递归的最大深度
worker_threads 0 // 可以启动的辅助工作线程的最大数量
1985年瑞典MySQL AB公司用basic语言开发,2008年MySQL AB被sun公司收购,2009年sun被Oracle收购。
特点:开源、占用资源少、适用于多种编程语言、支持客户端访问。
版本:
网址:www.mysql.com 下载专区里面,选择社区版的图形化安装包mysql installer msi进行下载。对于一般的开发而言,只需要自定义安装mysql server和mysql workbench就可以了。
命令窗口
启动mysql服务
打开mysql command line client窗口,输入密码root
图形化工具workbench
国内使用navicat更多,这里主要介绍navicat的使用:
函数的概念:按指定格式输入参数,返回正确结果的运算单元。