Oracle 11g SQL开发指南 学习笔记之从数据库表中检索信息

2.15 使用Order by子句对行进行排序

SELECT * from CUS ORDER BY last_name;默认情况下,Order by子句会按照升序对数据进行排序(较小的值先出现),可使用Describe关键字指定按照降序对数据进行排序(较大的值先出现),也可以使用ASC关键字显式地说明采用升序进行排序(升序是默认设置)

下面的SQL,对CUS表先根据first_name进行升序,然后再根据last_name进行降序排序
SELECT * from CUS ORDER BY FIRST_NAME ASC ,last_name DESC;

在Order by子句中,也可以根据列的次序指定对哪一列(也可以使用多列)进行排序:1表示按第一列,2表示按第2列,依次类推。如下:

SELECT * from CUS ORDER BY 2 ASC ,3 DESC;(和上述查询结果一致)

2.16 执行使用两个表的Select语句

数据库模式有多个表,这些表分别用于保存不同的数据。实际应用中,常常需要从多个表中检索信息——例如,检索产品类型名和实际产品的名称并一起显示。

例如,想要获得产品#3的名称及其产品类型的名称。产品的名称在products表的name列中,类型在products_types表的name中。这俩张表通过一个外键列product_type_id彼此关联在一起。products表的product_type_id列(外键)指向product_types表的product_type_id列(主键)。在查询中使用表连接可以完成上述任务。要在查询中将两个表连接起来,就需要在查询的From子句中同时指定2个表(From products,product_types),Where子句中指明两个表中的相关列(进行过滤)。一般情况下,连接中使用的列时一个表的主键和另一个表的外键。因为在连接条件中使用等于操作符(=),所以这种连接称为等连接(equijoin)。查询如下:

SELECT PRODUCTS."NAME" Product_Name,PRODUCT_TYPES."NAME"Product_Type from PRODUCTS,PRODUCT_TYPES 
where PRODUCTS.PRODUCT_TYPE_ID=PRODUCT_TYPES.PRODUCT_TYPE_ID
AND PRODUCTS.PRODUCT_ID=3;

2.17 使用表别名

表别名要在From子句中指定,且别名位于查询中其余列之前,下面的查询使用p作为products表的别名,pt作为product_types表的别名。

SELECT  p."NAME",PT.name  from PRODUCTS p,PRODUCT_TYPES pt WHERE p.PRODUCT_TYPE_ID=PT.PRODUCT_TYPE_ID ORDER BY p."NAME";

2.18 笛卡尔积

如果在多表查询中不指定连接条件,就会导致将一个表中的所有行都连接到另外一个表中的所有行上,这种情况就称为笛卡尔积(Cartesian product)。假设第一个表有50行,第二个表有100行。如果从这两个表中不使用连接条件来检索行,那么就会返回50*100=5000行。

2.19 执行使用多于两个表的select语句

连接可以用于连接任意多个表。连接数=查询中使用的表的总数-1。

现在考虑一个更复杂的例子,这个例子涉及4个表,因此需要使用3个连接。假设希望查询以下信息:

1)已购买过产品的顾客(来自purchasees表)

2)顾客的姓名(来自cus表)

3)顾客购买的产品名(来自products表)

4)产品类型名(来自product_types表)

完整的SQL为:

select c.first_name,c.last_name,p.name AS PRODUCT,pt.name AS TYPE from CUS c,purchases pr,products p,product_types pt 

Where c.customer_id=pr.customer_id

AND p.product_id = pr.product_id

AND p.product_type_id=pt.product_type_id

Order by p.name;

2.20 连接条件和连接类型

连接条件(join condition)可以分为两类:

·等连接(equijoin)在连接中使用等于操作符(=)

·不等连接(non-equijoin):在连接中使用除等号之外的操作符,例如<、>、Between等等。

·内连接(inner join):只有当连接中的列包含满足连接条件的值时才会返回一行。这就是说,如果某一行的连接条件中的一列是空值(Null),那么这行就不会返回。目前为止看到的都是内连接的例子。

·外连接(outer join):即使连接条件中的一列包含空值也会返回一行。

·自连接(self join):返回连接到同一个表中的行

2.20.1不等连接

不等连接在连接中使用除等于操作符之外的操作符,包括不等于(<>)、大于(>)、小于(<)、小于等于(<=)、大于等于(>=)、Like、IN和Between。很少碰到使移动不等连接的情况,但偶尔也会碰到,在那样的情况下就需要使用Between操作符。

使用不等连接来检索员工的工资和工资等级,工资等级用Between操作符来确定:

SELECT e.FIRST_NAME,e.LAST_NAME,e.TITLE,e.SALARY,SG.SALARY_GRADE_ID 
FROM EMPLOYEES e,SALARY_GRADES sg 
WHERE e.SALARY BETWEEN SG.LOW_SALARY AND SG.HIGH_SALARY
ORDER BY SALARY_GRADE_ID

在此查询中,如果员工的工资在工资等级的范围内,则Between操作符返回true。

2.20.2外连接

外连接(OUTER JOIN):外连不但返回符合连接和查询条件的数据行,还返回不符合条件的一些行。外连接分三类:左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)和全外连接(FULL OUTER JOIN)。
三者的共同点是都返回符合连接条件和查询条件(即:内连接)的数据行。不同点如下:
左外连接还返回左表中不符合连接条件单符合查询条件的数据行。
右外连接还返回右表中不符合连接条件单符合查询条件的数据行。
全外连接还返回左表中不符合连接条件单符合查询条件的数据行,并且还返回右表中不符合连接条件单符合查询条件的数据行。全外连接实际是上左外连接和右外连接的数学合集(去掉重复),即“全外=左外 UNION 右外”
说明:左表就是在“(LEFT OUTER JOIN)”关键字左边的表。右表当然就是右边的了。在三种类型的外连接中,OUTER 关键字是可省略的。


在外连接中,即使连接中的列包含一个空值,外连接也会返回一行。在连接条件中可以使用外连接操作符来执行一个外连接:Oracle特有的外连接操作符是使用圆括号括起来的加号(+)。

在下面的查询中,注意Oracle的外连接操作符(+)位于product表中product_type_id列(包含空值的列)相反的一边,也就是(+)在不为null的一边:

SELECT p."NAME",PT."NAME" FROM PRODUCTS p,PRODUCT_TYPES pt 
WHERE p.PRODUCT_TYPE_ID=PT.PRODUCT_TYPE_ID(+);

这样就可以查到即使连接条件中,不带有(+)的列值即使为null也能出现在查询结果中。

试与上句SQL比较查询结果的不同:

SELECT p."NAME",PT."NAME" FROM PRODUCTS p,PRODUCT_TYPES pt 
WHERE p.PRODUCT_TYPE_ID(+)=PT.PRODUCT_TYPE_ID;

1、左外连接和右外连接

外连接分为两类:

·左外连接和右外连接。

对于二者区别,考虑以下区别:

select ……

From table1,table2

……

假设这俩表对table1.column1和table2.column2进行连接,且table1中包含column1为空值的一行。要执行一个左外连接,where子句如下:

Where table1.column1 = table2.column2(+);--左连接:等号左边的列值可以为空,该条记录仍然出现在查询结果中。

右连接的where子句:

Where table1.column1 (+)= table2.column2;--右连接:等号右边的列值可以为空,该条记录仍然出现在查询结果中。

可想而知,如果table1和table2都包含其中一个为空值的行,则根据使用的是左外连接还是右外连接,会得到不同的结果。

2.外连接的限制

外连接的使用有一些限制:

1)只能在连接的一端使用外连接操作符,而不能在两端同时使用外连接操作符;

2)不能同时使用外连接条件和IN/OR操作符:where p.product_type_id (+) IN(1,2,3,4);

2.20.3 自连接

自连接是对同一个表进行连接。要执行一个自连接,必须使用不同的表别名来标识在查询中每次对表的引用(形式上相当于两个表)

现在考虑一个例子:employees表中有一列manager_id,它包含每个员工管理者的employee_id,如果员工没有管理者,则manager_id是空值。

可以使用一个自连接来显示每个雇员及其管理者的名字。下面的例子中employees表被引用了两次,分别使用了两个别名:w(worker)和m(manager)。别名w用于获得员工的姓名,而别名m则用于获得管理者的姓名。自连接是对w.mananger_id和m.employee_id进行的:

CEO是James Smith
SELECT
W.FIRST_NAME || ' '|| W.LAST_NAME || 'works for ' || M .FIRST_NAME || ' ' || M .LAST_NAME
FROM
EMPLOYEES W,
EMPLOYEES M

WHERE
W.MANAGER_ID = M.EMPLOYEE_ID
ORDER BY
W.FIRST_NAME;

2.21 使用SQL/92语法执行连接

目前为止我们看到的连接都是使用Oracle的连接语法。Oracle语法的基础是ANSI SQL/86标准。在开发Oracle Database 9i时,数据库还实现了ANSI SQL/92标准的连接语法,应该在查询中使用SQL/92标准的语法。

2.21.1 使用SQL/92标准语法执行两个表的内连接

之前已经提到过下面这个SQL

SELECT  p."NAME",PT.name  from PRODUCTS p,PRODUCT_TYPES pt WHERE p.PRODUCT_TYPE_ID=PT.PRODUCT_TYPE_ID ORDER BY p."NAME";

SQL/92引入了Inner Join和ON子句来执行内连接。下面使用Inner join和ON子句重写上面的查询:

SELECT p."NAME",PT."NAME" FROM PRODUCTS p INNER JOIN PRODUCT_TYPES ptON p.PRODUCT_TYPE_ID=PT.PRODUCT_TYPE_ID
ORDER BY p."NAME";

不等连接操作符和ON子句可以同时使用。

SELECT e.FIRST_NAME,e.LAST_NAME,e.TITLE,e.SALARY,SG.SALARY_GRADE_ID 
FROM EMPLOYEES e,SALARY_GRADES sg 
WHERE e.SALARY BETWEEN SG.LOW_SALARY AND SG.HIGH_SALARY
ORDER BY SALARY_GRADE_ID。

下面使用SQL/92标准重写这个查询:

SELECT e.FIRST_NAME,e.LAST_NAME,e.TITLE,e.SALARY,SG.SALARY_GRADE_ID 
FROM EMPLOYEES e INNER JOIN SALARY_GRADES sg 
ON e.SALARY BETWEEN SG.LOW_SALARY AND SG.HIGH_SALARY
ORDER BY SALARY_GRADE_ID;

2.21.2使用USING关键字简化连接

SQL/92标准可以使用Using子句对连接条件进一步简化,前提是查询满足以下限制:

1)查询必须是等连接

2)等连接中的列必须同名

我们将要执行的大部分连接都是等连接,如果总是对主键和外键使用相同的名字,就可以满足上面的这些限制。

下面的查询使用Using子句代替ON子句:

SELECT p."NAME",PT."NAME" FROM PRODUCTS p INNER JOIN PRODUCT_TYPES pt 

ON p.PRODUCT_TYPE_ID=PT.PRODUCT_TYPE_ID
ORDER BY p."NAME";

改写:

SELECT p."NAME",PT."NAME" FROM PRODUCTS p INNER JOIN PRODUCT_TYPES pt 

Using  (PRODUCT_TYPE_ID)
 ORDER BY p."NAME";

此时,如果希望查看product_type_id的值,则在select子句中只能指定该列名,不能使用表名或别名

SELECT p."NAME",PT."NAME" , PRODUCT_TYPE_ID FROM PRODUCTS p INNER JOIN PRODUCT_TYPES pt 

Using  (PRODUCT_TYPE_ID)
 ORDER BY p."NAME";

另外,在USING子句中也只能单独使用列名,不能使用 Using   (p.PRODUCT_TYPE_ID)

2.21.3 使用SQL/92执行多于两个表的内连接

select c.first_name,c.last_name,p.name AS PRODUCT,pt.name AS TYPE from CUS c,purchases pr,products p,product_types pt 
Where c.customer_id=pr.customer_id
AND p.product_id = pr.product_id
AND p.product_type_id=pt.product_type_id
Order by p.name;

重写:

SELECT
c.first_name,
c.last_name,
P . NAME,
pt. NAME AS TYPE
FROM
CUS c
INNER JOIN PURCHASES pr USING (CUSTOMER_ID)
INNER JOIN PRODUCTS P USING (PRODUCT_ID)
INNER JOIN PRODUCT_TYPES pt USING (PRODUCT_TYPE_ID)
ORDER BY
P . NAME;

多表连接实际上就是先对两个表进行连接,再将结果与另一个表进行连接,依次类推。

2.21.4 使用SQL/92执行多列的内连接

如果连接使用了两个表中的多个列,那么就可以在ON子句中使用AND操作符逐一列出这些列。示例如下:

From tb1 Inner join tb2

On tb1.col1 =tb2.col1

AND tb1.col2 = tb2.col2

可以使用USING子句进一步简化,条件是执行等连接,而且列名相同。如下:

From tb1 Inner join tb2 

using (col1,col2);

2.21.5 使用SQL/92执行外连接

前文中已经看到过如何使用外连接操作符(+)执行外连接,外连接操作符(+)是Oracle特有的语法。SQL/92使用一个不同的语法来执行外连接。SQL/92不使用(+)操作符,而是在select语句的from子句中指定连接类型,语法如下:

From table1 {LEFT | Right | FULL} OUTER JOIN table2;

其中:

1)table1和table2指定了希望连接的表;

2)LEFT说明希望执行左外连接

3)Right说明希望执行右外连接

4)Full说明希望执行全外连接;全外连接使用table1和table2中所有的行,包括连接列为空值的行。不能使用(+)操作符直接执行全外连接。

1.执行左外连接

下面看一下之前提到过的使用Oracle专有的(+)操作符执行一个左外连接:

SELECT p."NAME",PT."NAME" FROM PRODUCTS p,PRODUCT_TYPES pt 
WHERE PT.PRODUCT_TYPE_ID=p.PRODUCT_TYPE_ID(+) order By p.name;

下面使用SQL/92的Left outer Join关键字对这个查询进行重写:

SELECT p."NAME",PT."NAME" FROM PRODUCTS p LEFT OUTER JOIN PRODUCT_TYPES pt
Using (PRODUCT_TYPE_ID)
ORDER BY p."NAME";

2.执行右外连接---Right outer join

before:对表products执行右外连接。
SELECT p."NAME",PT."NAME" FROM PRODUCTS p,PRODUCT_TYPES pt 
WHERE p.PRODUCT_TYPE_ID(+) =PT.PRODUCT_TYPE_ID  order By p.name;

after:

SELECT p."NAME",PT."NAME" FROM PRODUCTS p RIGHT OUTER JOIN PRODUCT_TYPES pt 
using (PRODUCT_TYPE_ID) ORDER BY p."NAME";

3.执行全外连接

全外连接使用连接表中的所有行,包括连接中使用的列为空值的那些行。这样一来,不管是那个表中的对应连接条件中的列值为空值,都出现在结果集中。下面是一个SQL/92的Full Outer Join关键字的查询:

SELECT p."NAME",PT."NAME" FROM PRODUCTS p full outer join PRODUCT_TYPES pt
using(PRODUCT_TYPE_ID) ORDER BY p."NAME";

结果:

Hack Empire     DVD
Hero             DVD
Massage Ball     Null
Null             Book

适用场景??

2.21.6 使用SQL/92执行自连接

先看SQL/86标准执行自连接的语法

SELECT
W.FIRST_NAME || ' '|| W.LAST_NAME || 'works for ' || M .FIRST_NAME || ' ' || M .LAST_NAME
FROM
EMPLOYEES W,
EMPLOYEES M
WHERE
W.MANAGER_ID = M.EMPLOYEE_ID
ORDER BY
W.FIRST_NAME

重写:

SELECT
W.FIRST_NAME || ' ' || W.LAST_NAME || 'works for ' || M .FIRST_NAME || ' ' || M .LAST_NAME
FROM
EMPLOYEES W
INNER JOIN EMPLOYEES M ON W.MANAGER_ID = M .EMPLOYEE_ID
ORDER BY
W.FIRST_NAME;

2.21.7使用SQL/92执行交叉连接

前文已经提到如果忽略了两个表之间的连接条件会导致笛卡尔积。通过使用SQL/92的连接语法可以避免产生笛卡尔积,因为在对表进行连接时,通常必须通过一个ON或Using子句。

如果的确要使用笛卡尔积,SQL/92标准要求必须在查询中使用Cross Join关键字显式声明。

下面的查询中,就使用Cross Join关键字在product_types和products表之间生成一个笛卡尔积:

Select *

From product_types Cross Join products;


小结:使用SQL/92标准的连接时,注意JOIN 与ON/Using匹配的。




















你可能感兴趣的:(Oracle 11g SQL开发指南 学习笔记之从数据库表中检索信息)