【SQL开发实战技巧】系列(一):关于SQL不得不说的那些事
【SQL开发实战技巧】系列(二):简单单表查询
【SQL开发实战技巧】系列(三):SQL排序的那些事
【SQL开发实战技巧】系列(四):从执行计划讨论UNION ALL与空字符串&UNION与OR的使用注意事项
【SQL开发实战技巧】系列(五):从执行计划看IN、EXISTS 和 INNER JOIN效率,我们要分场景不要死记网上结论
【SQL开发实战技巧】系列(六):从执行计划看NOT IN、NOT EXISTS 和 LEFT JOIN效率,记住内外关联条件不要乱放
【SQL开发实战技巧】系列(七):从有重复数据前提下如何比较出两个表中的差异数据及对应条数聊起
【SQL开发实战技巧】系列(八):聊聊如何插入数据时比约束更灵活的限制数据插入以及怎么一个insert语句同时插入多张表
【SQL开发实战技巧】系列(九):一个update误把其他列数据更新成空了?Merge改写update!给你五种删除重复数据的写法!
【SQL开发实战技巧】系列(十):从拆分字符串、替换字符串以及统计字符串出现次数说起
【SQL开发实战技巧】系列(十一):拿几个案例讲讲translate|regexp_replace|listagg|wmsys.wm_concat|substr|regexp_substr常用函数
【SQL开发实战技巧】系列(十二):三问(如何对字符串字母去重后按字母顺序排列字符串?如何识别哪些字符串中包含数字?如何将分隔数据转换为多值IN列表?)
【SQL开发实战技巧】系列(十三):讨论一下常用聚集函数&通过执行计划看sum()over()对员工工资进行累加
【SQL开发实战技巧】系列(十四):计算消费后的余额&计算银行流水累计和&计算各部门工资排名前三位的员工
【SQL开发实战技巧】系列(十五):查找最值所在行数据信息及快速计算总和百之max/min() keep() over()、fisrt_value、last_value、ratio_to_report
【SQL开发实战技巧】系列(十六):数据仓库中时间类型操作(初级)日、月、年、时、分、秒之差及时间间隔计算
【SQL开发实战技巧】系列(十七):数据仓库中时间类型操作(初级)确定两个日期之间的工作天数、计算—年中周内各日期出现次数、确定当前记录和下一条记录之间相差的天数
【SQL开发实战技巧】系列(十八):数据仓库中时间类型操作(进阶)INTERVAL、EXTRACT以及如何确定一年是否为闰年及周的计算
【SQL开发实战技巧】系列(十九):数据仓库中时间类型操作(进阶)如何一个SQL打印当月或一年的日历?如何确定某月内第一个和最后—个周内某天的日期?
【SQL开发实战技巧】系列(二十):数据仓库中时间类型操作(进阶)获取季度开始结束时间以及如何统计非连续性时间的数据
【SQL开发实战技巧】系列(二十一):数据仓库中时间类型操作(进阶)识别重叠的日期范围,按指定10分钟时间间隔汇总数据
【SQL开发实战技巧】系列(二十二):数仓报表场景☞ 从分析函数效率一定快吗聊一聊结果集分页和隔行抽样实现方式
【SQL开发实战技巧】系列(二十三):数仓报表场景☞ 如何对数据排列组合去重以及通过如何找到包含最大值和最小值的记录这个问题再次用执行计划给你证明分析函数性能不一定高
【SQL开发实战技巧】系列(二十四):数仓报表场景☞通过案例执行计划详解”行转列”,”列转行”是如何实现的
【SQL开发实战技巧】系列(二十五):数仓报表场景☞结果集中的重复数据只显示一次以及计算部门薪资差异高效的写法以及如何对数据进行快速分组
【SQL开发实战技巧】系列(二十六):数仓报表场景☞聊聊ROLLUP、UNION ALL是如何分别做分组合计的以及如何识别哪些行是做汇总的结果行
文章目录
本篇文章讲解的主要内容是:从执行计划角度分析IN、EXISTS 和 INNER JOIN效率而不是死记网上结论、表的5种关联:INNER JOIN、LEFT JOIN、RIGHT JOIN 和 FULL JOIN 解析
【SQL开发实战技巧】这一系列博主当作复习旧知识来进行写作,毕竟SQL开发在数据分析场景非常重要且基础,面试也会经常问SQL开发和调优经验,相信当我写完这一系列文章,也能再有所收获,未来面对SQL面试也能游刃有余~。
相对查询单表中的数据来说,平时更常见的需求是要在多个表中返回数据。比如,显示部门10的员工编码、姓名及所在部门名称和工作地址。
select a.empno,a.deptno,b.dname
from emp a inner join dept b
on(a.deptno=b.deptno)
where a.deptno=10;
EMPNO DEPTNO DNAME
----- ------ --------------
7782 10 ACCOUNTING
7839 10 ACCOUNTING
7934 10 ACCOUNTING
另外有下面写法:
select a.empno,a.deptno,b.dname
from emp a,dept b
where a.deptno=b.deptno
EMPNO DEPTNO DNAME
----- ------ --------------
7369 20 RESEARCH
7499 30 SALES
7521 30 SALES
7566 20 RESEARCH
7654 30 SALES
7698 30 SALES
7782 10 ACCOUNTING
7788 20 RESEARCH
7839 10 ACCOUNTING
7844 30 SALES
7876 20 RESEARCH
7900 30 SALES
7902 20 RESEARCH
7934 10 ACCOUNTING
14 rows selected
其中,JOIN的写法是SQL-92的标准,当有多个表关联时,JOIN方式的写法能更清楚地看清各表之间的关系,因此,建议大家写查询语句时优先使用JOIN的写法。
下面先 创建一个表 emp2.
drop index IDX_ENAME;
DROP TABLE emp2 PURGE ;
CREATE TABLE emp2 AS
SELECT ename,job,sal,comm FROM emp WHERE job ='CLERK';
要求返回与表emp2(empno,job,sal)中数据相匹配的emp(empno,ename,job,sal,deptno)
信息。
有IN、EXISTS、INNER JOIN三种写法。为了加强理解,请大家看一下三种写法及其PLAN(此处用的是Oracle 11g)。
SQL> explain plan for select empno,ename,job,sal,deptno from emp where (ename,job,sal) in(select ename,job,sal from emp2);
Explained
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4039873364
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 67 | 6 (0)| 00:00:01 |
|* 1 | HASH JOIN SEMI | | 1 | 67 | 6 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| EMP | 15 | 780 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP2 | 4 | 60 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ENAME"="ENAME" AND "JOB"="JOB" AND "SAL"="SAL")
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
19 rows selected
SQL> EXPLAIN PLAN FOR SELECT empno,ename,job,sal,deptno FROM emp a
2 WHERE EXISTS (SELECT NULL
3 FROM emp2 b
4 WHERE b.ename = a.ename AND b.job = a.job
5 AND b.sal = a.sal) ;
Explained
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4039873364
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 67 | 6 (0)| 00:00:01 |
|* 1 | HASH JOIN SEMI | | 1 | 67 | 6 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| EMP | 15 | 780 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP2 | 4 | 60 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("B"."ENAME"="A"."ENAME" AND "B"."JOB"="A"."JOB" AND
"B"."SAL"="A"."SAL")
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
20 rows selected
(emp2.ename,emp2.job,ernp2.sal)没有重复行,所以这个查询可以直接改为INNER JOIN。SQL> EXPLAIN PLAN FOR SELECT a.empno,a.ename,a.job,a.sal,a.deptno from emp a
2 INNER JOIN emp2 b ON (b.ename = a.ename AND b.job = a.job AND b.sal =a.sal);
Explained
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 166525280
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 268 | 6 (0)| 00:00:01 |
|* 1 | HASH JOIN | | 4 | 268 | 6 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| EMP2 | 4 | 60 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP | 15 | 780 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("B"."ENAME"="A"."ENAME" AND "B"."JOB"="A"."JOB" AND
"B"."SAL"="A"."SAL")
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
20 rows selected
或许与大家想象的不一样,以上三个PLAN中JOIN写法利用了HASH JOIN(哈希连接),其他两种运用的都是HASH JOIN SEMI(哈希半连接),说明在这个语句中的IN与EXISTS效率是一样的。所以,在不知哪种写法高效时应查看PLAN,而不是去记固定的结论。
有很多人对这几种连接方式,特别是LEFT JOIN与RIGHT JOIN分不清,下面通过案例来解析一下。
首先建立两个测试用表。
DROP TABLE L PURGE ; DROP TABLE R PURGE;
--左表
CREATE TABLE L AS
SELECT 'left_1' AS str , '1' AS v FROM dual UNION ALL
SELECT 'left_2' AS str , '2' AS v FROM dual UNION ALL
SELECT 'left_3' AS str , '3' AS v FROM dual UNION ALL
SELECT 'left_4' AS str , '4' AS v FROM dual;
--右表
CREATE TABLE R AS
SELECT 'right_3' AS str , '3' AS v,1 as status FROM dual UNION ALL
SELECT 'right_4' AS str , '4' AS v,0 as status FROM dual UNION ALL
SELECT 'right_5' AS str , '5' AS v,0 as status FROM dual UNION ALL
SELECT 'right_6' AS str , '6' AS v,0 as status FROM dual;
该方式返回两表相匹配的数据,左表的"1、2"以及右表的"5、6"都没有显示。
JOIN写法
SQL>
SQL> select l.str as left_str, r.str as right_str
2 from l
3 inner join r
4 on (l.v = r.v)
5 order by 1, 2;
LEFT_STR RIGHT_STR
-------- ---------
left_3 right_3
left_4 right_4
该方式的左表为主表,左表返回所有的数据,右表中只返回与左表匹配的数据,"5、6"都没有显示。
join写法:
select l.str as left_str, r.str as right_str
from l
left join r
on (l.v = r.v)
order by 1, 2;
LEFT_STR RIGHT_STR
-------- ---------
left_1
left_2
left_3 right_3
left_4 right_4
加(+)写法
select l.str as left_str, r.str as right_str
from l, r
where l.v = r.v(+)
order by 1, 2;
该方式的右表为主表,左表中只返回与右表匹配的数据"3、4",而"1、2"都没有显示,右表返回所有的数据。
join写法
select l.str as left_str, r.str as right_str
from l
right join r
on (l.v = r.v)
order by 1, 2;
LEFT_STR RIGHT_STR
-------- ---------
left_3 right_3
left_4 right_4
right_5
right_6
加(+)写法
select l.str as left_str, r.str as right_str
from l, r
where l.v(+) = r.v
order by 1, 2;
该方式的左右表均返回所有的数据,但只有相匹配的数据显示在同一行,非匹配的行只显示一个表的数据。
JOIN写法
select l.str as left_str, r.str as right_str
from l
full join r
on (l.v = r.v)
order by 1, 2;
LEFT_STR RIGHT_STR
-------- ---------
left_1
left_2
left_3 right_3
left_4 right_4
right_5
right_6
6 rows selected
FULL JOIN 无(+ )的写法。
表emp中有一个字段mgr,其中是主管的编码(对应于emp.empno),如:
(EMPNO:7698,ENAME:BLAKE)-->(MGR:7839)-->(EMPNO:7839,ENAME:KING),说明BLAKE的主管就是KING
如何根据这个信息返回主管的姓名呢?
这里用到的就是自关联。也就是两次查询表emp,分别取不同的别名,这样就可以当作是两个表,后面的任务就是将这两个表和JOIN连接起来就可以。
为了方便理解,这里用汉字作为别名,并把相关列一起返回。
SELECT 员工.empno AS 职工编码,
员工.ename AS 职工姓名,
员工.job AS 工作,
员工.mgr AS 员工表_主管编码,
主管.empno AS 主管表_主管编码,
主管.ename AS 主管姓名
FROM emp 员工
LEFT JOIN emp 主管
ON (员工.mgr = 主管.empno)
ORDER BY 1;
职工编码 职工姓名 工作 员工表_主管编码 主管表_主管编码 主管姓名
----- ---------- --------- -------- -------- ----------
1001 test
7369 SMITH CLERK 7902 7902 FORD
7499 ALLEN SALESMAN 7698 7698 BLAKE
7521 WARD SALESMAN 7698 7698 BLAKE
7566 JONES MANAGER 7839 7839 KING
7654 MARTIN SALESMAN 7698 7698 BLAKE
7698 BLAKE MANAGER 7839 7839 KING
7782 CLARK MANAGER 7839 7839 KING
7788 SCOTT ANALYST 7566 7566 JONES
7839 KING PRESIDENT
7844 TURNER SALESMAN 7698 7698 BLAKE
7876 ADAMS CLERK 7788 7788 SCOTT
7900 JAMES CLERK 7698 7698 BLAKE
7902 FORD ANALYST 7566 7566 JONES
7934 MILLER CLERK 7782 7782 CLARK
15 rows selected
这一章主要介绍两块,之所以拿出来这两块说是因为:
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has
我看到这个错误:translationmissing:da.datetime.distance_in_words.about_x_hours我的语言环境文件:http://pastie.org/2944890我的看法:我已将其添加到我的application.rb中:config.i18n.load_path+=Dir[Rails.root.join('my','locales','*.{rb,yml}').to_s]config.i18n.default_locale=:da如果我删除I18配置,帮助程序会处理英语。更新:我在config/enviorments/devolpment
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.