本人曾去某金融软件公司面试,交流中面试官问的一个问题是:“如果有 A、B 两张表,A 表中有 2 条数据,B 表中有 200 条数据,请问 SELECT * FROM A,B 能查出多少条数据?”。

听到这个问题的瞬间我就懵了,因为我自己也做过近两年的面试官,所以我首先会想的就是他问这么没有实际意义(实际开发中几乎 100% 的查询都需要条件)的问题是想考察我什么呢?同时我心里也在想,这种逗号的写法本质上就是内连接,那答案是笛卡尔积吗?我刚想对面试官说:“我没这么写过,但我分析这种写法的结果应该是笛卡尔积,也就是 2×200 等于 400……”,正在组织语言的时候被面试官打断了,他说:“没关系!我就问问!……”

现在我们来仔细研究下这个问题

首先来创建 t6、t7、t8 共 3 张表,创建语句如下:

CREATE TABLE t6 AS SELECT LEVEL f1,6 f2,0 f3 FROM DUAL CONNECT BY LEVEL<=6;
CREATE TABLE t7 AS SELECT LEVEL f1,7 f2,0 f3 FROM DUAL CONNECT BY LEVEL<=7;
CREATE TABLE t8 AS SELECT LEVEL f1,8 f2,0 f3 FROM DUAL CONNECT BY LEVEL<=8;

然后来看看各个表中的数据分步

SQL> SELECT t6.* FROM t6;

        F1         F2         F3
---------- ---------- ----------
1 6 0
2 6 0
3 6 0
4 6 0
5 6 0
6 6 0 6 rows selected SQL> SELECT t7.* FROM t7; F1 F2 F3
---------- ---------- ----------
1 7 0
2 7 0
3 7 0
4 7 0
5 7 0
6 7 0
7 7 0 7 rows selected SQL> SELECT t8.* FROM t8; F1 F2 F3
---------- ---------- ----------
1 8 0
2 8 0
3 8 0
4 8 0
5 8 0
6 8 0
7 8 0
8 8 0 8 rows selected

接下来开始我们的实验

SELECT COUNT(1) res FROM t6 JOIN t7 ON t6.f1=t7.f1; -- res: 6
SELECT COUNT(1) res FROM t6 JOIN t7 ON t6.f2=t7.f2; -- res: 0
SELECT COUNT(1) res FROM t6 JOIN t7 ON t6.f3=t7.f3; -- res: 42
SELECT COUNT(1) res FROM t6 JOIN t7 ON 1=1; -- res: 42
SELECT COUNT(1) res FROM t6 JOIN t7 ON 1=2; -- res: 0

在 t6 和 t7 两张表中:f1 字段值中的 1~6 是相等的,所以结果集行数是 6×1 等于 6;f2 字段值则完全不想等,所以结果集行数是 6×0 等于 0;f3 字段值全都相等,所以结果集行数是 6×7 等于 42。

SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON t6.f1=t7.f1; -- res: 6
SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON t6.f2=t7.f2; -- res: 6
SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON t6.f3=t7.f3; -- res: 42
SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON 1=1; -- res: 42
SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON 1=2; -- res: 6

左连接的时候,会返回左边表中的所有行,如果左边表中的行在右边表中没有匹配行,则结果集中右边表中的列返回空值。在这里,t7.f1 与 t6.f1 有 6 行唯一匹配,所以结果集行数是 6×1 等于 6;t7.f2 与 t6.f2 完全不匹配,所以结果集行数就是 6;t7.f3 中有 7 行能匹配 t6.f3 中的任意行,所以结果集行数是 6×7 等于 42。

接下来回到本文一开始提出的那个问题,先看查询结果:

SELECT COUNT(1) res FROM t6,t7; -- res: 42

事实上这是一个交叉连接(一定有人会晕倒),交叉连接的标准写法是:

SELECT COUNT(1) res FROM t6 CROSS JOIN t7; -- res: 42

也许是工作久了的原因,可能大部分人都还记得内连接和外连接(左连接、右连接、全连接),因为内链接和左连接还经常用。同时,估计大部分人和我一样,已经把三大连接中的交叉连接给忘得一干二净了,原因也很简单,长时间没用了!

交叉连接最典型的特点就是没有 WHERE 子句,交叉连接返回连接表中所有数据行的笛卡尔积,在关系数据库中的笛卡尔积的结果就是交叉连接所涉及的表中行数之积。

其实 CROSS JOIN 后面也是可以跟 WHERE 子句的,不过那样它就相当于内连接了。我觉得可以理解为不写条件就相当于条件恒等,这时的结果集行数就是两个表中数据行数的乘积,也就是所谓的笛卡尔积。

最后附上同样从来都用不到的全连接的验证结果

SELECT COUNT(1) res FROM t6 FULL JOIN t7 ON t6.f1=t7.f1; -- res: 7
SELECT COUNT(1) res FROM t6 FULL JOIN t7 ON t6.f2=t7.f2; -- res: 13
SELECT COUNT(1) res FROM t6 FULL JOIN t7 ON t6.f3=t7.f3; -- res: 42
SELECT COUNT(1) res FROM t6 FULL OUTER JOIN t7 ON 1=1; -- res: 42
SELECT COUNT(1) res FROM t6 FULL OUTER JOIN t7 ON 1=2; -- res: 13

最最后附上全连接的定义:完全外部连接返回左边表和右边表中的所有行。当某行在一个表中没有匹配行时,则另一个表中的列将包含空值。如果表之间有匹配行,则整个结果集的行包含基表的数据。

本文链接http://www.cnblogs.com/hanzongze/p/oracle-sql-rows.html

版权声明:本文为博客园博主 韩宗泽 原创,作者保留署名权!欢迎通过转载、演绎或其它传播方式来使用本文,但必须在明显位置给出作者署名和本文链接!个人博客,能力有限,若有不当之处,敬请批评指正,谢谢!

Oracle 查询结果集行数分析的更多相关文章

  1. 查询执行成本高(查询访问表数据行数多)而导致实例 CPU 使用率高是 MySQL 非常常见的问题

    MySQL CPU 使用率高的原因和解决方法_产品性能_常见问题_云数据库 RDS 版-阿里云 https://help.aliyun.com/knowledge_detail/51587.html ...

  2. Oracle查询库中记录数大于2千万的所有表

    Oracle查询库中记录数大于2千万的所有表 假如当前用户拥有select any table权限,则可以使用下列sql语句: select table_name, num_rows from dba ...

  3. MS SQL查询所有表行数,获取所有数据库名,表名,字段名

    1.获取所有数据库名 --SELECT Name FROM Master..SysDatabases ORDER BY Name -- 2.获取所有表名: --SELECT Name NAMEtemp ...

  4. 解析oracle的rownum,数据库查询结果返回行数设置

    对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,而且rownum不能以任何表的名称作为前缀 ...

  5. CI中获取读操作的结果集行数+获取写操作的影响行数

    本质:读操作,用mysql_num_rows函数,写操作用mysql_affected_rows函数 mysql_num_rows() 返回结果集中行的数目.此命令仅对 SELECT 语句有效.要取得 ...

  6. iOS开发- 查询项目代码行数

    ...事实上, 这功能也没什么用. 就是查询一个项目总的代码行数. 玩玩倒是能够. 方法: 在终端以下依次输入: cd 项目文件 find . "(" -name "*. ...

  7. Hibernate 查询sql结果行数的几种方法

    一.前言 这个东西,难度几乎没有,就是繁琐. 一条简单的select count(*) from table_name 都能有多种书写方式. 总是忘,这里记录下. 一 .通过Criteria 查询 C ...

  8. oracle:ORACLE 实际返回的行数超出请求的行数

    写的存储过程,执行后一直报实际返回的行数超出请求的行数的错误. 原因:select prdt_id into prdt_id from.... 两个变量名称相同造成的..哎  第一个变量换成大写..问 ...

  9. ORACLE 查询不走索引的原因分析,解决办法通过强制索引或动态执行SQL语句提高查询速度

    (一)索引失效的原因分析: <>或者单独的>,<,(有时会用到,有时不会) 有时间范围查询:oracle 时间条件值范围越大就不走索引 like "%_" ...

随机推荐

  1. 通过游戏来学习CSS的Flex布局

    在复习Flex 布局的时候发现的了几个有趣的小游戏,在这里分享并记录几个有难度的答案 1. Flexbox Froggy 通过调整CSS样式来使各种青蛙回到对应的荷叶上,游戏默认难度为Beginner ...

  2. ntp---时钟同步服务

    NTP--时钟同步服务 地球分为东西十二个区域,共计 24 个时区 格林威治作为全球标准时间即 (GMT 时间 ),东时区以格林威治时区进行加,而西时区则为减. 地球的轨道并非正圆,在加上自转速度逐年 ...

  3. 封装redis

    封装redis import redis # r = redis.Redis() class MyRedis(): def __init__(self,ip,password,port=6379,db ...

  4. 锐捷交换机配置DHCP SERVER给固定的MAC地址分配静态IP

    今天突发奇想,想给自己的手机分配固定地址,使得接入公司无线网络时每次都取到同一ip地址,这样可以排除认证登录问题. 上网溜达一下,记录下锐捷官方的[常见问题]如下,经验证可行. 需求: 给MAC地址为 ...

  5. SElinux安全子系统---学习

    SElinux是一个强制访问控制的安全子系统,是为了让各个服务进程都受到约束,只能获取到属于自己的资源 SElinux有三种配置模式: 1:enforcing--强制启动安全配置策略,拦截不合法的请求 ...

  6. Cmd命令 查看端口被占用

    1)第一步 打开cmd命令窗口,输入命令:netstat -ano|findstr 输入端口号 2)第二步 继续输入命令:tasklist|findstr  第一步查询到的进程号 3)第三步 根据第二 ...

  7. iOS浏览器 new Date() 返回 NaN

    问题 项目中某个地方用到了倒计时,因此打算通过 new Date() 函数实现.但在 iPhone 真机测试的时候,显示的结果不符合预期.通过调试发现 iOS 中 new Date('2017-01- ...

  8. TCPDF说明文档

    TCPDF说明文档 一.首先调用TCPDF文件 require_once('tcpdf.php'); 二.实例化TCPDF类 页面方向(P =肖像,L =景观).测量(mm).页面格式 $pdf = ...

  9. ArrayList源码理解

    ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Col ...

  10. .net core2.1 使用 dynamic 类型报错

    在net core2.0项目中使用 dynamic 无法编译通过 异常信息:缺少编译器要求的成员"Microsoft.CSharp.RuntimeBinder.CSharpArgumentI ...