目录
简介
在Android中存储数据有时会用到数据库,Android给我们提供了 一系列的API来操作数据库,非常简单,我们只需要输入对应的SQL语句,甚至不懂SQL语句,只传入对应的参数即可使用。还有一些第三方库,如GreenDao,OrmLite等都极大的简化了对数据库的一些操作。这样虽然我们不需要对数据库有多了解一样能实现功能,但是在面对复杂操作时,对SQL语句的熟练使用就显得尤为重要了。因为在Android我们只要是利用SQL语句对表操作,所以本文主要介绍SQL的使用,只是简单介绍了数据库一些相关的概念,这样能有更加清晰的认识。
数据模型
按照计算机系统的观点对数据进行建模。
概念模型
也称为信息模型,即按照用户的观点来对数据和信息建模
- 实体(Entity):客观存在并可互相进行区分的事物称为实体
- 属性(Attribute):实体所具有的某一特性称为属性,一个实体可有若干个属性来刻画。
- 键(KEY):唯一标识实体的属性集称为键,一般分为超键、候选键、主键以及外键。
- 域(Domain):属性的取值范围称为该属性的域。
- 实体型(Entity type):用实体名以及其属性名集合来抽象和刻画同类实体称为实体型
- 实体集:同型实体的集合称为实体集
现实世界的实体进入数据库
- 1.讲现实世界中的客观对象抽象为概念模型
- 2.把概念模型转化为某一DBMS(数据库管理系统)支持的数据模型
键的概念
- 超键(super key):在关系中能唯一区分实体的属性集称为关系模式中的超键。
- 候选键(candidate key):不含有多余属性的超键(每一个属性都能区分实体)
- 主键(primary key):用户选作区分实体发的一个候选键(foreign key)
- 外键:在某个关系A中的主键出现在另一个关系B中,此时关系A中的该主键称为关系B中的外键。
例子说明: 员工(身份证号、姓名、年龄、性别)假设姓名也是唯一的超键:身份证号、姓名、姓名+年龄、姓名+性别、身份证号+年龄、身份证号+性别候选键:身份证号、姓名
数据库设计范式
数据库设计范式简单的说就是关系数据库在设计时需要遵循的一种规范,数据库范式按照要求从低到高分为6大范式,即第一范式(1NF)~第六范式(6NF)。在第一范式的基础上进一步满足更多要求的称为第二范式,一次类推。越高的范式数据库冗余越小,一般来说,数据库只需要满足第三范式(3NF)就行了。
第一范式
是数据库设计的最基本的要求,不满足1NF的数据库不是关系型数据库
所谓第一范式就是指数据库表的每一列都是不可分割的基本数据项,同一列中只能有一个属性(也就是说一个属性下不能再分出其他的属性来)
第二范式
第二范式是在第一范式的基础上建立起来的,即满足2NF必须先满足1NF
只出现在复合主键的数据库表中
第二范式要求数据库表中的每个实例或者行必须可以被唯一地区分,所以实体必须设置主键,并且实体的属性必须完全依赖于主键,不得出现非主键属性部分依赖于主键的情况。
主键为学号+课程名称,而学分依赖于学号,这就是所谓的非主键属性依赖于主键的情况,这是不符合2NF的,出现了数据的冗余(存储多余的数据,浪费空间),解决办法就是拆成3张表。
第三范式
要求一个数据库表中不包含已在其他表中已包含的非主关键字信息(非主键属性不能出现在第二张表中)
非主键属性重复了,完全可以根据编号(主键)去查询部门简介和名称
数据库设计的完整性约束
实体完整性约束
每个实例或者行的主键都不能为空
参照完整性约束
外键可以为空值;当外键不为空时,其取值只能等于参照的主键的某个值
数据库的约束
约束是表级强制执行的规则,当表中数据有相互依赖性时,可以保护数据不被删除
约束的类型:
- 表级约束和列级约束,他们两者在作用上没有任何的区别,但通常如果某个约束用于于不止一个列时,只能使用表级约束的形式来进行表达,如果多个字段组成耨表的联合主键时。
- 列级约束: 在定义列的时候:列名 约束类型 表级约束 在定义完所有的列后:列名,列名,。。。 约束类型
oracle有如下类型的约束:
not null:非空
primary key:主键约束
foreign key:外键约束
check:检查约束
unique key:唯一性约束
not null(非空约束)
create table student(
name varchar2(10),
sex varchar(5) not null,
age integer)
primary key(主键约束)
表级方式定义主键
create table student(
name varchar2(19),
sex varchar2(10),
age integer,
constraint student_age_pk primary key(age)
);
把age定义为主键(student_age_pk:约束的名字有一定的规范:表名主键名约束类型)
列级方式定义主键
create table student(
name varchar2(19) primary key,
sex varchar2(10),
age integer);
foreign key(外键约束)
create table emp(
empno number(4),
ename varchar2(10) not null,
job varchar2(9),
deptno number(7,2) not null,
constraint emp_deptno_fk foreign key(deptno) references dept (deptn)
);
--references dept (dept):外键所对应的主键所在的表 关键字 主表 主键
SQL语句
- 常用数据类型 2.子查询(单行子查询和多行子查询)
- select语句 条件查询 模糊查询 简单去掉重复的查询结果 关于空值
- order by
- 单行函数
- 字符函数
- 数值处理函数
- 日期处理函数
- 类型转换函数
- 通用函数
- 组(聚合)函数
- 语句的执行顺序
- insert
- detect
- update
- 事务与锁
- DDL语句(数据定义语言)
- 多表联合查询
- 集合
- 视图
- 约束条件
- 添加注释
- 索引
- 经典案例
常用数据类型
- varchar2(size):可变长度的字符串,最大长度为size个字节,size最大值为4000,最小值为1
- char(size):固定长度的字符数据,其长度为size个字节,最大值为2000,最小值和默认值为1,不管实际的长度为多少都会分配指定的size个字节
- number(p,s):有效位数为p且精度为s的数值(小数点后有s位)p的取值范围为1到38
- date:有效日期范围从公元前4712年1月到公元后4712年12月31日
- long:可变长度的字符数据,其长度可达2G个字节
查询
子查询
- 子查询在主查询的前一次执行
- 主查询使用子查询的结果
- 子查询要用括号括起来
- 将子查询放在比较运算符的右边
- 子查询中不要加ORDER BY子句
应用场景:例如那些雇员的工资比林志玲的高?
单行子查询
查询结果为一行
-
单行子查询只能使用单行比较运算符 =,>,>=,<,<=,<>
select name,job from emp where job = (select job from emp where empno = 7369); select ename,job,sal from emp where sal=(select min(sal) from emp)
相关子查询
多行子查询
- 查询结果为多行
- 多行子查询只能使用多行比较运算符
IN:等于列表中的任何值
ANY:比较子查询返回的每一个值,只要其中一个满足条件就返回true
ALL:比较子查询返回的每一个值,要其中所有的值都满足条件才返回true
使用IN:
select empno,ename,job from emp where deptno in(select deptno from emp where ename = 'SMITH' or ename ='MITLER');
使用ANY
<ANY : 指小于最大值
ANY : 指大于最小值
-
ANY:与IN等价
select empno,ename,job from emp where sal <ANY (select sal from emp where job = 'clerk')
使用ALL
- <ALL : 指小于最小值
- ">ALL" : 指大于最大值
select empno,ename,job,sal from emp where sal > ALL(select avg(sal) from emp GROUP BY depton)
SQL语句
- select语句
select 列名 form 表名select name from student
select * from student :查询所有的列
select name,sex from student
-
select name as myname from student:队列中使用别名
- 查询结果显示的列用别名显示(as 用别名显示)
- 之前是结果列名为name as后为myname
- 不写as就要加引号或者空格:select name "myname" form student
-
列使用算数表达式:
- select name,sal,sal+100 from student: 查询sal和sal+100
-
关于空值
- 空值为不可用,不知道,不适用的值
- 空值不等于0或者空格
- 包含空值的算数表达式等于空
-
连接操作符
- 可将列或者字符与其他列连接起来,用双竖线标识(||)
- 产生的结果是一个字符表达式
- 使用连接操作符查询,返回结果是一个连接后的结果(每个结果的连接)
- select name || sex as new from student:将name和sex的查询结果连接起来显示并设置查询结果对应的列名为new
-
简单去掉重复的查询结果
- 使用distinct关键字可以是某列中重复的值不显示
- distinct操作会引起排序,通过排序去掉重复的记录
- distinct必须放在第一列的前面,只能实现单列去重
- select distinct sex from student
-
条件查询
- select 列名 from 表名 where 条件
- where后面不能使用别名
-
模糊查询
- 使用like运算符进行通配查询
- 查询条件可以包含文字字符或数字
- %:表示0或多个字符
- _:表示一个字符
select name from student where name like 'S%' :只显示以S开头的姓名
select name from student where name like '_A%' :只显示第二个字符为A的名字
select naem from student where name like '%A_B%' :只显示含有A_B的名字(\:转义字符)
order by
- 使用order by可以将记录进行排序
- ASC:升序(默认的),DESC:降序排列
- order by 只能放到所有select语句的最后
select name,sex,age from student order by age asc:按照age进行降序排列
select name,sex,age,sal from student order by age asc,sal desc:按照age降序排列,如果相等则在按照sal升序排列
单行函数
- 用于操作数据项
- 可以接受参数并返回一个值
- 对每一个返回行起作用,每一行返回一个结果
- 可使用转换函数修改数据类型
- 可使用嵌套形式
- 常见的单行函数包括字符、数字、日期处理函数、类型转换函数、逻辑处理函数等
字符函数
-
lower:将字符串全部变为小写
select name,sex from student where LOWFR(name) = 'blake'; 查询姓名为blake的相应属性,不管姓名是大小写还是大小写混写的都能查出
upper:将字符串全部变为大写
initcap:将字符串的第一个字母变为大写
concat:将两个字符串拼接起来
-
substr:截取字符串
select substr('helloword',2,5) from dual;--从第二个开始数5个
-
length:返回字符串的长度
select length(t.empfirstname) from employee t;
-
instr:在一个字符串中定位子字符串的位置(没有的话返回值为0)
select instr('hellword','w')from dual;--查询w在hellword中的位置
左补齐函数(lpad)
-
右补齐函数(rpad)
select e.empfirsname,rpad(e.empfistname,10,'&') from employees e;--设置长度为10,不够的用&补齐
-
replace:替换函数
select replace('ABCDFG','D','www') from dual;--用www替换D
trim(leading|trailing|both y from x):从x中截去单个字符y
-
both:截去两边的;leading:从左边;traiing:从右边
select trim(both 'h' from 'hooojdhh') from dual;--截去两边的h
数值处理函数
-
1.round:保留指定的位数(按四舍五入)
SELECT round(5.75), round(5.75, 1), round(15.75, -1) FROM dual;--1代表保留一位小数,-1表示个位也四舍五入
-
trunc:直接去掉小数点,没有四舍五入
SELECT trunc(5.75), trunc(5.76, 1), trunc(15.75, -1) FROM dual;--1表示保留一位小数,直接去掉后面的,不四舍五入
-
mod:去余数
select mod(1600,300) from dual;--返回结果为100
-
abs:去绝对值
select t.quotedprice -100 from order_details t where t.ordernumber =354 and t.productnumber = 13;--返回
sign(x)返回x的符号
若x<0,返回-1;若x=0,返回0;若x>0,返回1
-
floor(x)返回小于或等于x的最大整数
select floor(5.8),floor(-5.6) from dual;
-
ceil(x)返回大于或等于x的最小整数
select ceil(5.8),ceil(-5.6) from dual;
power(x,y)返回x的y次幂
日期处理函数
-
sysdate:返回系统的当前时间
select sysdate from dual;
-
add_months(x,y):返回x加上y个月的结果,如果y为负值,就是减去
select add_months(sysdate,10) from dual;
-
last_day(x):返回包含x月的最后一天
select last_day(date '1993-04-28') from dual;--返回结果为1993-04-30
-
next_day(x,day):从x时间开始,返回下一个day的时间值
select next_day(sysdate,'星期一') from dual;--从系统的当前时间开始,返回下一个星期一的日期
-
months_between(x,y):返回x和y之间有多少个月(x-y),可以是负数
select months_between(sysdate,date '1993-04-28')/12 from dual;--计算出某个人的周岁
round(date,month/day):
Month 1-15日算上一个月,15日后算下一个月
Year 1-6月算上一年,7-12月算下一年
select round(date'2014-7-16','month') from dual;--返回2014-8-1 select round(date'2014-7-16','year') from dual;--返回结果为2015-1-1
-
trunc
select trunc(date'2014-7-16','month') from dual;返回结果为2014-7-1
类型转换函数
数据类型转换包含隐士类型转换和显示类型转换
隐士类型转换:系统自动转换
显示类型转换:调用相应的函数转换
TO_CHAR:字符串转换(其他类型转换为字符串)
TO_NUMBER:数值转换
TO_DATE:日期转换
- TO_CHAR
将日期转换为字符串格式
必须用单引号括起来,大小写不敏感
有一个fm元素,用于填补空格或者禁止前面的零
使用逗号分离日期
TO_CHAR(date,'fmt')
常用的日期格式:
YYYY:四位数表示的年
YEAR:拼写出的年
MM:两位数字的月
MONTH:全月明(例如:sepember)
DD:两位数字表示的月
DAY:全天名
select name,TO_CHAR(hiredate,'fmDD Month YYYY') HIREDATE from emp
-
TO_NUMBER:将字符串转化为数值TO_NUMBER(char)
select * from emp where deptno = TO_NUMBER('30')
-
TO_DATE:将字符串转换为日期TO_DATE(char,['fmt'])
select TO_DATE('2006-05','YYYY-MM') from DUAL
通用函数
-
nvl(value,srt):如果第一个参数不为null,就返回第一个参数,如果为null就返回第二个参数
select nvl(e.name,'name is null') from employee e;
-
nvl2(value,x,y):如果value为null就返回y,否则返回x
select nvl2(s.class_id,1,2) from students s;
-
nullif(x,y):如果相等返回null,不相等则返回x;
select nullif(s.sex,'男') from students s;
case表达式:(选择表达式)
Case国际sql通用支持的,使用case可移植更好。相当于在SQL中执行if语句 CASE 可用于允许使用有效表达式的任意语句或子句。 例如,可以在 SELECT、UPDATE、DELETE 和 SET 等语句以及 select_list、IN、WHERE、ORDER BY 和 HAVING 等子句中使用 CASE。
select e.salary,
case e.type_id
when 1 then e.salary*2
when 2 then e.salary*3
when 3 then e.salary*4
eles e.salary*5
end
as new_salary from employee e;
说明:当typeid为1时,薪水2,当typeid为2时,薪水3,当type_id为3时,薪水4,其他情况下薪水5;
组(聚合)函数
-
max(),min().avg():注意单行与多行不能放在一起
select max(e.aslary),e.type_id from employee e;--会直接报错的,单行结果与多行不能放在一起
-
count:统计函数 : 统计字段时不统计null的
select count(*) from employee;--统计该表一共有多少条记录(里面加任意的数字也可以count(2)) select count(e.manager_id) from employee e;--按照某个字段统计,空值不统计
-
group by:分组
结合分组函数使用
group by后面的列可以不出现在select后边,但出现在select后面的列必须出现在group by子句里面
如果select列表中既有普通列又有分组函数,则必须使用group by子句
聚合分组函数的条件限定不能使用where,只能使用having,且用了having必须使用group by。select e.division*id,avg(e.salary) from employees2 e group by e.division*id;--求每个部门的工资
语法的执行顺序
1.select 2.from 3.where 4.group by 5.组函数 6.having 7.order by
说明:having与where功能一样,就是执行的顺序不一样eg:select e.division_id,avg(e.salary) from employees2 e group by e.division_id where avg(e.salary)>150000;--会报错的,因为where比组函数(avg)先执行,在执行where的时候,avg(e.salary)还没有算出来,所以会出错,换成having就没事了。
-
insert into(插入语句)
插入时注意完整性约束条件(外键的取值)
插入的时候插入到首行insert into 表名(插入的字段)values(字段对应的值) insert into student values(3,'name','sex',12); insert into student(id,name) values(4,'name'); insert into student values(5,'''name','sex',12);
插入的名字为'name insert into student(name,sex) values(&Name,'nan');
&:变量,在执行该语句时,会让你输入name要插入的值(Name变量名自己起的) 一次插入多条语句,要查入得值从另一个表中取数据 insert into student(name,sex,age) select name,sex,age from student2 where id>10;
-
delete(删除语句) : delect from 表名 条件
delect from student where id=3
-
update(修改语句) : update 表名 set 字段名=要修改的值 条件
update student set name=gfdd where id=2; update studnet set name=gggg,sex=nv where id=3;
事务
一组sql语句一块执行,要么一起成功,要么一起失败 以commit开始
commit:提交eg:commit
-
rollback:回滚(撤销)eg:rollback
commit;select * from customers;insert into customers values(6,'gfd','red',date '1993-04-28',null); insert into customers values(7,'gfd','red',date '1993-04-28',null); savepoint A;--添加保存的点,回滚时可以指定到该位置 insert into customers values(8,'gfd','red',date '1993-04-28',null); savepoint B; insert into customers values(9,'gfd','red',date '1993-04-28',null); rollback to A;--回滚到A点
锁:保证数据库的一致性(同步):自添加锁
T1执行 update students set name='gfd' where id=3; 如果T2想修改id=3的数据,必须等T1提交后才能修改(也就是说提交后自动释放锁)
死锁
T1 update students set name='gfd' where id=3;
update students set name='gfd' where id=4; T2 update students set name='gfd' where id=4;
update students set name='gfd' where id=3;
说明:在T1,T2执行完第一条语句时,再执行下一条语句时,都被各彼此锁着,所以都不能执行下去了。 就出现了死锁的状态,oracle数据库会自动解锁一条语句
DDL语句(数据定义语言)
对表的操作可以通过DDL语句进行,包括:
-
create:创建新表,必须以字母开头,访问其他用户的表时需要加上用户名的前缀
create table dept(deptno number(2),dname varchar2(14),loc varchar2(3)); create table dept30 as select empno,ename,sal*12 ANNSAL,hiredate from emp where deptno=30;--数据从别的表中拷贝
-
创建联合主键的表
create table emp( emp_id integer, emp_name varchar2(20) not null, emp_bir date default sysdate primary key(emp_id,emp_name) );
alter:更改表的结构(字段)
alert table 表名 add (增加的列名 类型,。。。。。);--增加列
alert table 表名 modify (修改的列名 类型);--修改列
alert table 表名 rename column 要修改的列名 to 新的列名;--修改列名
alter table 表名 rename to 新的表名;--修改表名
alert table 表名 drop column 要删除的列名;--删除列
alert table dept30 add (job varchar2(9));
alert table dept30 modify (job varchar2(15));
alert table dept30 raname column deptname to dname;alert table dept30 drop column job;
- drop:删除表
表中的所有数据将被删除
事物被自动提交
所有的索引被删除
不能回退
彻底删除表
drop table 表名;--删除指定的表
- truncate:快速删除表中的所有记录
直接删除全部的记录,无法指定删除条件
无法回退
只会删除数据,会保留表的结构(字段),可以再次插入数据
速度快于delect
truncate table 表名;--删除指定的表
约束条件
-
primary key(主键约束)
-
在创建的表的时候指定
create table emp(emp_id integer primary key)
-
在表创建完成后添加主键约束
alter table stu add primary key (emp_id);
-
-
foregin key(外键约束)
-
两张表没有建立外键关系
alter table stu add foregin key(stu_id) references xi(xi_id)
-
删除外键的时候,相应表中与该外键的有关的记录也全部删除
alter table stu add foregin key(stu_id) references xi(xi_id) on delete cascade
-
删除外键的时候,相应表中与该外键的有关的列全部设置为null
alter table stu add foregin key(stu_id) references xi(xi_id) on delete set null
-
-
unique(不能重复约束)
alter table emp add unique(emp_name);--可以插入null(null值可以重复)
-
check(取值范围约束)
alter table emp add check(em_sex in ("男","女"));alter table emp add check(em_id>0);
索引
使用索引大大加快查询的速度
对数据量大的,经常使用的表才去创建索引(需要维护的)
查询的时候与正常的一样
create index 索引名 on 表名(字段名。。。。);--创建索引delete index 索引名;--删除索引
视图
可以隐藏一些信息
虚拟的表(不真实存在,基表的数据删除时,视图中的数据也会删除)
可以进行增删改查(对视图表中的数据改变时,基表的数据也会改变)
只要视图中能看到的,基表中肯定能看到
create or replace view ch_view as select * from products p where p.price<15;--创建视图
select * from ch_view;--查询视图insert into ch_view values(14,3,'fff','ggg',12);--插入数据
添加注释
comment on table 表名 is ‘注释’;--表添加注释
comment on column 表名.字段名 is ‘注释’;--字段添加注释
多表联合查询
没有指定连接条件的多表查询将造成笛卡尔积的结果
笛卡尔积结果:两个表中所有数据的集合都会查询出来
多表连接查询中的连接类型
内连接:返回符合特定连接条件的查询记录
-
等值连接:返回符合指定连接条件的值,这些值是相等关系
select * from products p,product_type pt where p.type_id = pt.type_id; select * from products p inner join prodect_type on p.type_id = pt.type_id;--inner join on 条件
-
非等值连接:返回符合指定连接条件的值,这些值不是相等关系
select * from products p,product_types pt where p.product_type_id <> pt.product_type_id;--<>:不等于
自然连接:特指在同一张表内通过特定连接条件查询符合连接条件的值
select * from products p natural inner join purchases pt;--自动按着相等的去连接,不用加条件了 在emp中每一个员工都有自己的mgr(经理),并且每一个经理自身也是公司的员工,自身也有自己的mgr。我们需要将每一个员工自己的名字和经理的名字都找出来。
select worker.ename,'work for',manager.ename from emp worker,emp managetr where worker.mgr = manager.empne work for:连接字符串
外连接:不仅返回符合连接条件的记录,也返回指定表中的不符合连接条件的记录
-
左外连接:先对A表和B表做内连接,再把A表中没有匹配的结果集添加进去形成新的结果集(相应的右表的值(对应A表没有匹配的)为null)
select * from newdept left outer join newemp on newdept.deptid = newemp.deptid;--outer可以省略 。。。。。。。where a.deptno = b.deptno(+);--左连接
-
右外连接: 先对A表和B表做内连接,再把B表中没有匹配的结果集添加进去形成新的结果集(相应的左表的值(对应B表没有匹配的)为null)也返回
select * from newdept right outer join newemp on newdept.deptid = newemp.deptid 。。。。。。。where a.deptno(+) = b.deptno;--右连接
全外连接:在内连接的基础上,把左右两表中不符合连接条件的记录都返回
在emp中每一个员工都有自己的mgr(经理),并且每一个经理自身也是公司的员工,自身也有自己的mgr。我们需要将每一个员工自己的名字和经理的名字都找出来。
select worker.ename,'work for',manager.ename from emp worker,emp managetr
where worker.mgr = manager.empnework for:连接字符串
用SQL语句列出EMP表中所有部门的详细信息以及对应的部门人数
select a.* , b.* from dept a,(select deptno,count(*) from emp group by deptno) b where a.deptno = b.deptno(+)
- 全外连接
用SQL语句列出NEWEMP表和NEWDEPT表中所有部门和员工的详细信息:
select * from newdept full outer join newemp on newdept.deptid = newemp.deptid
集合
集合中的元素可以把一条记录或者一个字段当做一个元素
用了集合再排序的时候,order by 字段的位置(例如 1):只能用数字了
intersect:交集
-
minus:减集
- 在一张表中显示了,就不在另一张表中出现了(A表 minus B表):显示B表去除与A表相同的部分
-
union all:并集(加all不去重)union :去重
select * from (select * from (select * from employees2 e order by e.salary desc) where rownum<11 minus select * from (select * from employees2 e order by e.salary desc) e where rownum<4) order by 6;--用到了集合再排序只能使用数字了
经典例子
根据时间统计胜负数
执行sql语句变成为:
select
t_date,
(select count(*) from t where t_status='胜' and t_date=e.t_date) 胜,
(select count(*) from t where t_status='负' and t_date=e.t_date) 负
from t e group by t_date order by e.t_date;
两张表中的数据运算
select kc.mc "种类",kc.s1-(select sum(s1) from ck where ck.mc = kc.mc ) "剩余量" from KC;
一次修改多条记录
update employees e set e.salary =
case e.employee_id
when 1 then 5555
when 2 then 6666
end
where e.employee_id<3;
多表联查
购买数量超过一个的产品名,顾客名以及购买的数量(3张表)
select * from products;
select * from customers;
select * from purchases;
-
第一种方法
select * from customers c inner join (select * from products p inner join purchases pr on p.product_id=pr.product_id) a on a.customer_id=c.customer_id where a.quantity>1;
-
第二种方法
select * from (products p inner join purchases pr on p.product_id=pr.product_id and pr.quantity>1) inner join customers c on c.customer_id=pr.customer_id;
-
第三种方法
select * from products p,purchases pr,customers c where p.product_id=pr.product_id and pr.customer_id=c.customer_id and pr.quantity>1;
四表联查
有如下几张表:
部门表:organization(orgid ,orgName)
商品表:Goods(goodsid,goodsName)
销售单(单头):sale(billid,billdt,orgid,status)
销售单(单体):sale_item(billid,goodsid,qty)
orgid:组织编码;
orgName:组织名称;
billid:单据编号
billdt:订单日期
查询“销售一部”本月的商品销售明细(商品编码。商品名称,销售日期,销售数量)
select * from organization o,goods g,sale s,sale_item si
where
o.orgid=s.orgid and g.goodsid=si.goodsid ands.billid=si.billid and orgName="销售一部" and billdt>trunc(sysdate) and billdt < last_day(sysdate);