《SQL必知必会》(8-15)

1. 创建计算字段(field)

1.1 拼接(concatenate)

此操作在Access和SQLServer用加号(+),在DB2、Oracle、PostgreSQL、SQLite和Open Office Base中用两个竖杠(||)完成。

selec trtrim(vend_name) || '(' || rtrim(vend_country) || ')'as vend_title from vendors order by vend_name;


rtrim()去掉字符串右边空格,ltrim()去掉字符串左边空格。as可重新命名拼接好的字段。

但是在MySQL和MariaDB中,必须使用特殊函数concat。

select concat(vend_name,'(',vend_country,')'from vendors order by vend_name; 

1.2 执行算数计算

select prod_id,quantity,item_price,quantity*item_price as expended_price from Orderitems where order_num=20008;

 SQL 算术操作符 

操作符

说明

+

-

*

/

2. 函数

虽然所有类型的函数一般都可以在每个DBMS中使用,但是各个函数的名称和语法可能极其不同。

2.1 文本处理函数

函数

说明

Left()

返回字符串左边的字符

Length()

返回字符串长度

Lower()

将字符串转换为小写

Ltrim()

去掉字符串左边的空格

Rtrim()

去掉字符串右边的空格

Right()

返回字符串右边的字符

Soundex()

返回字符串的soundex值

Upper()

将字符串转换为大写

soundex是一个将任何字符串转换为描述其语音表示的字母数字模式的算法。soundex考虑了类似的发音字符和音节,使得能对字符串进行发音比较而不是字母比较。soundex不是SQL概念,但多数DBMS都提供对soundex的支持(除了Microsoft Access和PostgreSQL不支持)。

例如,Customers表中有一个顾客Kids Place,其联系名为Michelle Green。但如果这是错误的输入,此联系名实际应该是MichaelGreen,显然按正确的联系名搜索不会返回数据。若:select cust_name,cust_contact from customers where soundex(cust_contact)=soundex('Michael Green');


select vend_name, upper(vend_name) as vend_name_upcase from vendors orderby vend_name;

 

2.2 日期和时间处理函数

日期和时间函数在SQL中很不一致,可移植性最差。

Ø  检索2012年的所有订单,SQLServer中输入:

select order_num from orders wheredatepart(yy,order_date)=2012;

Ø  Access中输入:select order_num from orders where datepart('yyyy',order_date)=2012;

Ø  oracle中:select order_num from orders where to_number(to_char(order_date,'yyyy'))=2012;to_char()函数用来提取日期的成分,to_number()用来将提取出的成分转换为数值,以便能与2012比较。


Ø  MySQL和MariaDB中,select order_num from orders whereYear(order_date)=2012;

Ø  SQLite中:select order_num from orders where strftime('%y',order_date)='2012';

2.3 数值处理函数

函数

说明

Abs()

返回一个数的绝对值

Cos()

返回一个角度的余弦

Exp()

返回一个数的指数值

Pi()

返回圆周率

Sin()

返回一个数的正弦

Sqrt()

返回一个数的平方根

Tan()

返回一个数的正切

3. 汇总数据

3.1 聚合函数

3.1.1  AVG()函数-返回平均值

Ø  计算某列平均值:selectavg(prod_price) as avg_price from products;

Ø  计算特定列平均值:selectavg(prod_price) as avg_price from products where vend_id='DLL01';

3.1.2  count()-计数

Ø  计算所有行数:selectcount(*) as num_cust from customers;

Ø  计算特定列的行数:selectcount(cust_email) as num_cust from customers;

3.1.3  max()-返回最大值

selectmax(prod_price) as max_price from products;

在用于文本数据时,返回按该列排序后的最后一行。

3.1.4  min()函数-最小值

selectmin(prod_price) as min_price from products;

在用于文本数据时,返回按该列排序后的最前面一行。

3.1.5  sum()-求和

Ø  单列:selectsum(quantity) as items_ordered from orderitems where order_num=20005;

Ø  多列:selectsum(item*quantity) as total_ordered from orderitems where order_num=20005;

3.2聚集不同值(distinct)

使用distinct参数,只考虑不同值。例如:select avg(prod_price) as avg_price from products;

注:distinct()不能用于count(*),可用于count()。

3.3 组合聚集函数

selectcount(*) as num_items,min(prod_price) as price_min, max(prod_price) as price_min, avg(prod_price) as price_avg from products;

4. 分组数据

使用分组可以将数据分为多个逻辑组,对每个组进行聚集计算。

4.1 创建分组

例如:select vend_id,count(*) as num_prods from products groupby vend_id;

 

group by子句指示DBMS按vend_id排序并分组数据,这就会对每个vend_id而不是整个表计算num_prods一次。

关于group by子句:

Ø  groupby子句可以包含任意数目的列,因而可以对分组进行嵌套,更细致地进行分组。

Ø  如果在group by子句中嵌套了分组,数据将在最后指定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)。

Ø  groupby子句中列出的每一列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在select中使用表达式,则必须在group by子句中指定相同的表达式。如果在select中使用表达式,则必须在group by子句中指定相同的表达式。不能使用别名。

Ø  大多数SQL实现不允许group by列带有长度可变的数据类型(如文本或备注型字段)。

Ø  除聚集计算语句外,select语句中的每一列都必须在group by子句中给出。

Ø  如果分组列中包含具有NULL值的行,则NULL将作为一个分组返回,如果列中有多行null值,它们将分为一组。

Ø  groupby子句必须出现在where语句之后,order by语句之前。

4.2 过滤分组(having)

having和where的区别联系:

Ø  where的所有技术和选项都适用于having。使用方法相同,只是关键字有区别。

Ø  where是过滤行,having是过滤分组。换言之,where在数据分组前进行过滤,having在数据分组后进行过滤。where排除的行不包括在分组中,这可能会改变计算值,从而影响having子句中基于这些值过滤掉的分组。

列出具有两个以上产品且其价格大于等于4的供应商:select vend_id,count(*) as num_prods from products where prod_price>=5groupby vend_id havingcount(*)>=2;


where子句先过滤出所有prod_price至少为4的行,然后按vend_id分组数据,having子句过滤出计数为2或2以上的分组。

4.3 分组和排序

groupby与orderby

Order by

Group by

对产生的输出排序

对行分组,但输出可能不是分组的顺序

任意列都可以使用

只可能使用选择列或表达式列,而且必须使用每个选择列表达式

不一定需要

如果与聚集函数一起使用列(或表达式),则必须使用

例如:select order_num, count(*) as items from orderitems groupby order_num havingcount(*)>=3;

 

select order_num, count(*) as items from orderitems groupby order_num havingcount(*)>=3orderby items,order_num;


5. 子查询(嵌套查询)

5.1 利用子查询过滤

本书中使用的数据库表都是关系表。(具体见附录)。订单存储在两个表中。每个订单包含订单编号、客户ID、订单日期,在order表中存储为一行。各订单的物品存储在相关的orderitem表中。order表不存储顾客信息,只存储顾客ID。顾客的实际信息存储在customers表中。例如:列出订购物品RGAN01的所有顾客。

selectcust_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='RGAN01'));

 

5.2 作为计算字段使用子查询

假如需要显示customers表中每个顾客的订单总数。订单与相应的顾客ID存储在orders中。

select cust_name,

                 cust_state,

                 (selectcount(*)

                 from orders

                 where orders.cust_id=customers.cust_id) as orders

from customers

orderby cust_name;

 

6. 联结表(join)

6.1 创建联结-完全限定列名

select vend_name,prod_name,prod_price from vendors v,productsp where v.vend_id=p.vend_id;

 

在联结两个表时,实际要做的是将第一个表中的每一行与第二个表中的每一个行配对。where子句作为过滤条件,只包含那些匹配给定条件的行。若没有联结条件,返回的结果是笛卡尔积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。而不管它们逻辑上能否配在一起。

联结多张表:

 

6.2 内联结(inner join)

内联结即等值联结(equijoin),它基于两个表之间的相等测试。前面例子亦可使用如下语句实现:select vend_name,prod_name,prod_price from vendors v innerjoin products p onv.vend_id=p.vend_id;

12.1的示例可用如下语句实现:select cust_name,cust_contact from customers c,orderso,orderitems s wherec.cust_id=o.cust_id ando.order_num=s.order_num and prod_id='RGAN01';

6.3 使用表别名

SQL允许给表起别名主要有两个原因:一是缩短SQL语句;二是允许在一条select语句中多次使用相同的表。一般数据库使用as,oracle中直接指定。

6.4 不同类型的联结

除了上述内联结,还有三种其他联结:自联结(self-join)、自然联结(natural join)和外联结(outer join)。

Ø  自联结

例如,要给与Jim Jones同一公司的所有顾客发送一封邮件。这个查询要求首先找出Jim Jones工作的公司,然后找出在该公司工作的顾客。

selectc1.cust_id,c1.cust_name,c1.cust_contact from customers c1,customers c2 wherec1.cust_name=c2.cust_name and c2.cust_contact='Jim Jones';

  

Ø  自然联结

无论何时对表联结,应该至少有一列不止出现在一个表中,标准的联结返回所有数据,相同的列甚至多次出现。自然联结排除多次出现,使每一列只返回一次。select c.*,o.order_num,o.order_date,s.prod_id,s.quantity,s.item_pricefrom customers c,orderso,orderitems s wherec.cust_id=o.cust_id ando.order_num=s.order_num and prod_id='RGAN01';

 

我们建立的每个内联结都是自然联结。

Ø  外联结

外联结关联了那些在相关表中没有关联行的行,分为左关联(left outer join)和右关联(right outer join)。left是指outer join左边的表。下面例子从left outer join左边的表(customers)中选择所有行。例如:select c.cust_id,o.order_num from customers c leftouterjoin orders o onc.cust_id=o.cust_id;

 

select c.cust_id,o.order_num from customers c rightouterjoin orders o onc.cust_id=o.cust_id;


有的数据库还支持全外联结(full outer join),它检索两个表中的所有行并关联那些可以关联的行。与左外关联和右外关联包含一个表的不关联的行不同,全外联结包含两个表的不关联的行。selectc.cust_id,o.order_num from customers c fullouterjoin orders o on c.cust_id=o.cust_id;

 

6.5 使用聚合函数的联结

例如:select c.cust_id,count(o.order_num) as num_ord from customers c fullouterjoin orders o on c.cust_id=o.cust_id groupby c.cust_id;

  

7. 组合查询(UNION)

7.1 组合查询

SQL允许执行多个查询(多条select语句),并将结果作为一个查询结果集返回。

7.2 创建组合查询

7.2.1  使用union

使用union很简单,就是在每条select语句之间加上关键字union即可。

select cust_name,cust_contact,cust_email from customers where cust_state in ('IL','IN','MI') UNIONselectcust_name,cust_contact,cust_email from customers where cust_name='Fun4All';

 

或者使用select cust_name,cust_contact,cust_email from customers where cust_state in ('IL','IN','MI') or cust_name='Fun4All'

7.2.2  union使用规则

Ø  必须使用由两条或两条以上的select语句组成。

Ø  union中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)。

Ø  列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含转换的类型(例如,不同的数值类型或不同的日期类型)。

7.2.3  包含或取消重复的行

union从查询结果集中自动去除了重复的行,若要返回所有匹配的行,可用unionall,而不是union。

7.2.4  对组合查询结果排序

在用union组合查询时,只能使用一条orderby子句,它必须位于最后一条select语句之后,DBMS将用它来排序所有select语句返回的所有结果。

select cust_name,cust_contact,cust_email from customers where cust_state in ('IL','IN','MI') UNIONselectcust_name,cust_contact,cust_email from customers where cust_name='Fun4All'orderby cust_name,cust_contact;

注:以上实例都是使用union来组合针对同一表的多个查询。实际上,union在需要组合多个表的数据时也很有用,即使是有不匹配列名的表,在这种情况下,可以将union与别名组合,检索一个结果集。union操作的各结果集,只要保证列数相同,并且各列的数据类型一致即可,并不要求具有统一的列名,没有别名时,结果为第一个select语句的列名,有别名时结果列名为别名。例如:

select order_num, cust_id from orders unionselect order_item,prod_id from orderitems;

 

select order_num num, cust_id idfrom orders unionselect order_item,prod_id from orderitems;

 

8.插入数据(insert)

8.1 数据插入

插入有几种方式:

Ø  插入完整的行。

Ø  插入行的一部分。

Ø  插入某些查询结果。    

8.1.1    插入完整的行

比较安全的做法是加入列名。insert into customers(cust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip) values('1000000007',NULL,NULL,'Toy Land','123 Any Street','New York','NY','11111');

8.1.2    插入部分行

省略列:如果表的定义允许,则可以在insert操作中省略某些列。省略的列必须满足一下某个条件。

Ø  该列定义为允许NULL(无值或空值)。

Ø  在表定义中给出默认值。这表示如果不给出值,将使用默认值。

例如:insert into customers(cust_id,cust_name,cust_address,cust_city,cust_state,cust_zip)  values('1000000008','Toy Land','123 Any Street','New York','NY','11111');

8.1.3    插入检索出的数据(insert…select)

例如想把另一表中的顾客列合并到customers表中。insert into customers(cust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip) select cust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip from custnew;

说明:

Ø  insert select语句不一定要求列名匹配,它使用的是列的位置,因此select中的第一列(不管其列名)将用来填充表列中指定的第一列,以此类推。

Ø  insert select中的select语句可以包含where子句。

Ø  insert通常只插入一行。插入多行,必须使用多个insert语句。insert select例外,不管select返回多少行,都将被插入。

8.2 表的复制

要将一个表的内容复制到一个全新的表(运行中创建的表),可以使用select into语句。

select * into custcopy from customers;

要想只复制部分的列,可以明确给出列名,而不是使用*通配符。

MariaDB、MySQL、Oracle、PostgreSQL和SQLite使用的语法稍有不同:

create table custcopy as select * from customers;

关于使用select into的说明:

Ø  任何select选项和子句都可以使用,包括where和group by;

Ø  可利用联结从多个表插入数据;

Ø  不管从多少个表检索数据,数据都只能插入到一个表中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值