SQL必知必会2

在1中我们主要讲了在单个表上的查询,而在2中我们将会扩展到多个表中,以适应更广泛的作业

11.使用子查询
11.1子查询(subquery)
即嵌套在其他查询中是查询

11.2利用子查询进行过滤
SELECT order_num
FROM orderitems
WHERE prod_id='RGAN=01'


SELECT cust_id
FROM orders
WHERE order_num IN (SELECT order_num
                                        FROM orderitems
                                        WHERE prod_id='RGAN=01');
在SELECT中,子查询由内向外处理      

SELECT cust_name,cust_contact
FROM customers
WHERE cust_id IN(SELECT cust_id
                                FROM orders
                                WHERE order_num IN (SELECT order_num
                                                                        FROM orderitems
                                                                        WHERE prod_id='RGAN=01'));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
作为子查询的SELECT语句只能查询单个列。企图查询多个列将返回错误

11.3作为计算字段使用子查询
从customers表中检索每个顾客的订单数

SELECT cust_name,
                cust_state,
                (SELECT COUNT(*)
                FROM orders
                WHERE orders.cust_id=customers.cust_id) AS orders
                --完全限制列名,告诉SQL比较orders表中的cust_id与customers表中的          
                cust_id相比较
FROM customers
ORDER BY cust_name;
1
2
3
4
5
6
7
8
9
对于这种问题有不止一种解决方案,JION也可以。

12.联结表
12.1联结
12.1.1关系表
举个例子,我们会将供应商信息与其供应的商品分开存放,因为每个供应商可能会有多种商品 
1.统一供应商生存的每种商品,其供应信息是相同的,不必对这些信息重复录入 
2.供应商信息发生变化,只需改动一次即可 
我们的原则就是相同的数据出现多次并不是一件好事,关系型数据库正是基于此建立。 
关系表的设计就是把数据分成多个表,一类数据一个表,不同 的表之间通过某些共同的值连接。

12.1.2为什么使用联结表
联结:用一条SELECT语句检索存储在多个表中的数据

12.2常见联结-指定联结的表及联结的方式
SELECT vend_id,prod_name,prod_price
FROM vendors,products
WHERE vendors.vend_id=products.vend_id;
1
2
3
12.2.1WHERE子句的重要性
WHERE子句作为过滤条件,只包含那些匹配给定条件(这里是联结条件)的行 
若在联结中没有过滤条件,就会令两个表中的每一行都和另一个表中的每一行匹配,即为笛卡尔积,这是我们应该避免的。

12.2.2内联结
SELECT vend_id,prod_name,prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id=products.vend_id;
1
2
3
12.2.3联结多个表
SELECT prod_name,vend_id,prod_name,prod_price,quantity
FROM orderitems,vendors ,products
WHERE vendors.vend_id=products.vend_id 
AND orderitems.vend_id=products.prod_id
AND order_num=2007;
这个例子显示订单2007中的物品。
1
2
3
4
5
6
联结的表越多,性能下降的越厉害,不要联结不必要的表。一般DBMS对联结的表个数有限制。

返回11章中的例子
SELECT cust_name,cust_contact
FROM customers
WHERE cust_id IN(SELECT cust_id
                                FROM orders
                                WHERE order_num IN (SELECT order_num
                                                                        FROM orderitems
                                                                        WHERE prod_id='RGAN=01'));
用JOIN 改写
SELECT cust_name,cust_contact
FROM customers,orders,orderitems
WHERE customers.cust_id=orders.cust_id
AND orderitems.order_num=orders.order_num
AND prod_id='RGAN01';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
13.创建高级联结
13.1对表使用别名
缩短语句;允许在一条SELECT语句总多次使用相同的表

对上个例子进行改写
SELECT cust_name,cust_contact
FROM customers AS C,orders AS O,orderitems AS OI
WHERE C.cust_id=O.cust_id
AND OI.order_num=O.order_num
AND prod_id='RGAN=01';
1
2
3
4
5
6
13.2使用不同类型的联结
自联结self jion 自然联结natural join 外联结outer join

13.2.1自联结??
多次引用同一个表的子查询

SELECT C.*,O.order_num,O.order_date,OI.prod_id,OI.quantity,OI.item_price
FROM customers AS C,orders AS O,orderitems AS OI
WHERE C.cust_id=O.cust_id
AND OI.order_num=O.order_num
AND prod_id='RGAN=01';
1
2
3
4
5
13.2.2外联结
SELECT customers.cust_id,orders.order_num
FROM customers LEFT OUTER JOIN orders
ON  customers.cust_id=orders.cust_id;
--左外联结,以左边的表为基准,右边的表多的舍去,少的为NULL

SELECT customers.cust_id,orders.order_num
FROM customers RIGHT OUTER JOIN orders
ON  customers.cust_id=orders.cust_id;
--右外联结,以右边的表为基准

SELECT customers.cust_id,orders.order_num
FROM customers  OUTER JOIN orders
ON  customers.cust_id=orders.cust_id;
--全外联结
1
2
3
4
5
6
7
8
9
10
11
12
13
14
13.3使用带聚集函数的联结
聚集函数与联结一起使用 
检索所有顾客及每个顾客所下的订单个数

SELECT customers.cust_id
              COUNT(orders.order_num) AS num_ord
FROM custmers INNER JOIN orders
ON customers.cust_id=orders.cust_id
GROUP BY customers.cust_id;
1
2
3
4
5
14.组合查询
用UNION将多条SELECT语句组合成一个SELECT语句

14.1组合查询
适用情况 
1.在一个查询中从不同的表返回结构 
2.对一个表执行多个查询,按一个查询返回数据 
任何具有多个WHERE子句的SELECT语句都可以作为一个组合查询

14.2创建组合查询
14.2.1使用UNION
SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_state IN('IL','IN','MI')

SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_name='Fun4ALL';
上面的例子用UNION联结
SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_state IN('IL','IN','MI')
UNION
SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_name='Fun4ALL';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
14.2.2UNION的使用规则
1.UNION中的每个查询包含相同的列,表达式或者聚集函数,但是各个列不要求以相同的顺序写出 
2.列数据类型必须兼容,类型不必完全相同,但必须是DBMS可以隐含转换的类型(例如,不同的数值类型和日期类型)

14.2.3包含或取消重复的行
SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_state IN('IL','IN','MI')
UNION
SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_name='Fun4ALL';
--去掉结果集中重复的行

SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_state IN('IL','IN','MI')
UNION ALL
SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_name='Fun4ALL';
--直接将两个结果集进行组合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
14.2.4对组合查询结果排序
SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_state IN('IL','IN','MI')
UNION
SELECT cust_name,cust_contct,cust_email
FROM customers
WHERE cust_name='Fun4ALL';
ORDER BY cust_name,cust_contct,
--必须位于最后一条SELECT语句之后
1
2
3
4
5
6
7
8
9
15.插入数据INSERT
15.1数据插入
1.插入完整的行 
2.插入一部分数据 
3.插入某些查询结果

15.1.1插入完整/部分行
INSERT INTO customers(cust_id,
                     cust_name,
                     cust_adress,
                     cust_name,
                     cust_city,
                     cust_zip)
VALUES('',
       '',
       '',
        '',
        '',
        'NULL')
1
2
3
4
5
6
7
8
9
10
11
12
–列名与插入的相应数据要对应,写入的列名可以不用对应原表中的列名顺序,如果对应的列名里没有要插入数据,写入NULL, 
–也可以不用对一行的所有列都插入,插入哪些列,就写哪些列。

15.1.3插入检索的数据
INSERT INTO customers(cust_id,
                                        cust_name,
                                        cust_adress,
                                        cust_name,
                                        cust_city,
                                        cust_zip)
SELECT cust_id,
            cust_name,
            cust_adress,
            cust_name,
            cust_city,
            cust_zip
 FROM custnew;
 --从custnew表中读出数据并插入customers表中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
##15.2从一个表复制到另一个表

 SELECT *
 INTO custcopy
 FROM customers;
1
2
3
16.更新和删除表
16.1更新数据UPDATE
1.更新特定行 
2.更新所有行 
不要省略WHERE子句 
更新客户1000005的电子邮件

UPDATE customers
SET cust_email='[email protected]'
WHERE cust_id='10000005';
1
2
3
更新多列

UPDATE customers
SET cust_email='[email protected]'
        cust_contact='sam robert'
WHERE cust_id='10000005';
1
2
3
4
删除指定的列

UPDATE customers
SET cust_email=NULL
WHERE cust_id='10000005'
1
2
3
16.2删除数据DELETE
DELETE FROM customers
WHERE cust_id='10000005';
1
2
删除的是内容,而非表

16.3更新和删除的原则
1.一定要注意WHERE子句 
2.保证每个表都有主键 
3.在UPDATE和DELETE使用WHERE之前,一定要先用SELECT进行测试,保证过滤的是正确的记录,以防编写的WHERE的子句不正确 
4.使用强制实施引用完整性的数据库,这样DBMS将不允许删除其数据与表相关联的行。 
5.有的DBMS允许数据管理员施加约束,防止执行不带WHERE子句的UPDATE和DELETE.

17.创建和操作表
17.1
1.交互式界面创建 
2.SQL语句创建

17.1.1表创建基础CREATE TABLE
1.新表的名字,在关键字CREATE TABLE 之后 
2.表列的名字和定义,用逗号分隔

CREATE TABLE products
(
prod_id  CHAR(10)  NOT NULL,
prod_name  CHAR(254)  NOT NULL,
prod_price  DECIMAL(8,2)  NOT NULL,
prod_desc  VARCAR(1000)  NULL
);
1
2
3
4
5
6
7
指定表名时,若该表名已经存在,则需要先删除该表,而不是简单的覆盖

17.1.2使用NULL值
对于列的属性定义,NOT NULL即不允许该列出现空值,否则将会报错,列默认允许为NULL值。

17.1.3指定默认值
CREATE TABLE products
(
prod_id  CHAR(10)  NOT NULL,
prod_name  CHAR(254)  NOT NULL,
prod_price  DECIMAL(8,2)  NOT NULL DEFAULT 1,
prod_desc  VARCAR(1000)  NULL
);
--在插入的行如果不给出值,自动赋予默认值。
1
2
3
4
5
6
7
8
17.2更新表ALTER
ALTER对表的列及表名进行操作,UPDATE对表的行进行操作

ALTER TABLE vendors
ADD vend_phone CHAR(20);

ALTER TABLE vendors
DROP COLUMN  vend_phone;            
1
2
3
4
5
17.3删除表
DROP TABLE custcopy;

17.4重命名表
RENAME TABL cusucpoy TO custnew;

18.使用视图
18.1视图
视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询。 
这是12章的一个例子,查询订购了某种商品的顾客

SELECT cust_name,cust_contact
FROM customers,orders,orderitems
WHERE customers.cust_id=orders.cust_id
AND orderitems.order_num=orders.order_num
AND prod_id='RGAN01';
1
2
3
4
5
现在,假如我们可以把整个查询包装成一个名为productcustomers的虚拟表,就可以对上述查询进行简化

SELECT cust_name,cust_contact
FROM productcustomers
WHERE prod_id='RGAN01';
1
2
3
18.1.1为什么使用视图
1.重用SQL语句 
2.简化复杂的SQL操作 
3.使用表的一部分而不是整个表 
4.保护数据,授予用户访问表的特定部分的权限,而非整个数据。 
5.更改数据格式额表示。视图可返回与底层表的表示和格式不同的数据 
视图是一种查看储存在别处的数据的一种设施,视图本身不含任何数据,只是从别处查询数据,在添加和更改这些表中的数据时,将会返回更改过的 数据

18.1.2视图的规则和限制
1.视图必须唯一命名 
2.创建视图的数据没有限制 
3.必须有足够的访问权限 
4.视图可以嵌套,即可以利用从其他视图检索出的数据来构建视图 
5.在视图查询中禁止使用ORDER BY 子句 
6.有些DBMS要求对返回的列进行命名,如果列是计算字段,需要使用别名 
7.视图不能索引,也不能有关联的触发器或默认值 
8.有些DBMS把视图作为只读的查询,这表示可以从视图检索数据,但不能将数据写回底层表

18.2创建视图
CREATE VIEW 同样必须先删除相同的视图,再进行覆盖

18.2.1利用视图简化复杂的联结
对于上述例子,productcustomers怎么创建

CREATE VIEW productcustomers AS
SELECT cust_name,cust_contact,prod_id
FROM customers,orders,orderitems
WHERE customers.cust_id=orders.cust_id
AND orderitems.order_num=orders.order_num
--这个视图联结了三个表,返回已订购了任意产品的所有顾客的列表

SELECT cust_name,cust_contact
FROM productcustomers
WHERE prod_id='RGAN01';
1
2
3
4
5
6
7
8
9
10
18.2.2用视图重新格式化检索出的数据
第7章例子

SELECT RIRIM(vend_name) + ‘(‘+RIRIM(vend_country)+’)’
               AS  vend_title
FROM vendors
ORDER BY vend_name;
1
2
3
4
现在,假设我们经常需要这个格式化的结果,不必每次在需要的时候都进行这种拼接,而是创建一个视图,使用它即可。把此语句转化为视图。

CREATE VIEW vendorlocations AS
SELECT RIRIM(vend_name) + ‘(‘+RIRIM(vend_country)+’)’
               AS  vend_title
FROM vendors;

SELECT * FROM vendorlocations;
--结果与第七章相同
1
2
3
4
5
6
7
18.2.3用视图过滤不想要的数据
CREATE VIEW customersemaillist AS
SELECT cust_id,cust_name,cust_email
FROM customers
WHERE cust_email IS NOT NULL;

SELECT *
FROM customersemaillist;
1
2
3
4
5
6
7
18.2.4使用视图与计算字段
第7章例子

SELECT prod_id,
               quality,
               item_price,
               quantity*item_price AS expanded_price
FROM orderitems
WHERE order_num=20008;

利用视图重构
CREATE VIEW orderitemexpanded AS
SELECT order_num,
               prod_id,
               quality,
               item_price,
               quantity*item_price AS expanded_price
FROM orderitems;

SELECT *
FROM orderitemexpanded
WHERE order_num=20008;
--------------------- 
作者:xjh163 
来源:CSDN 
原文:https://blog.csdn.net/xjh163/article/details/79406578 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/liusongping123/article/details/84062389