SQL语言是一门相对来说简单易学却又功能强大的语言,它能让你快速上手并很快就能写出比较复杂的查询语句。但是对于大多数开发者来说,使用SQL语句查询数据库的时候,如果没有一个抽象的过程和一个合理的步骤,很可能会在写一些特定的SQL查询语句来解决特定问题的时候被卡住。

这里主要讲述下SQL查询的一些基本理论,以及写查询语句的抽象思路。

SQL查询的简介

SQL语言起源于1970年E.J.Codd发表的关系数据库理论,所以可以说SQL是为关系数据库服务的。而对于SQL查询,是指从数据库中取得数据的子集。

子集指的就是从一个或多个表中提取特定的字段和字段对应的记录。

可以说,SQL中无论多复杂的查询,都可以抽象成如上面的过程。

精确查询的前置条件

想要正确取得所需要的数据子集,除了需要思路正确并将思路正确转变为对应SQL查询语句之外,还有很重要的一点是需要数据库有着良好的设计。这里的良好设计指的是数据库的设计符合业务逻辑。如果数据库设计得很烂,那数据查询起来就很困难,要达到精确查询也就变得困难起来。

举个简单的例子,A表中有a字段,B表中也有a字段,在业务处理的过程中,A表中的a字段可能和B表中的a字段发生了分歧,这时候是要取A表中的a字段的值还是取B表中的a字段的值,也就成了一个问题。

两种方式,同一种结果

在SQL中,取得相同的数据子集可以用不同的思路或不同的SQL语句,因为SQL源于关系数据库理论,而关系数据库理论又源于数学,思考如何构建查询语句时,都可以抽象为两种方法。

关系代数法

关系代数法的思路是对数据库进行分步操作,最后取得想要的结果。

SELECT NAME FROM USERS WHERE AGE > 20;

关系代数的思路描述上面语句为:对USERS表进行投影(选择列)操作,然后对结果进行筛选,只取得年龄大于20的结果。

关系演算法

相比较关系代数法而言,关系演算法更多关注的是取得数据所满足的条件。比如上面SQL用关系演算法可以被描述为:我想得到所有年龄大于20的员工的姓名,部门和年龄。

两种算法的区别

对于简单的查询语句来说,上面两种方法都不需要,因为可能用脚就可以想出来了,只是问题在于很多情况下查询语句会非常复杂,这时候就用两种算法去区分描述的优势才会表现出来。

对于关系演算法来说,更多关注的是所取出信息所满足的条件;而对于关系代数法来说,更多关注的是如何取出特定的信息。简单地说,关系演算法表示的是【what】,而关系代数法表达的是【how】。SQL语句中所体现的思路,有些时候是关系代数法,有些时候是关系演算法,还有些会是两种思路的混合。

对于某些查询情况,关系代数法可能会更简单;而对于另外一些情况,关系演算法则会显得更直接;还有一些情况则是需要混合两种思路。所以这两种思维方式在写SQL查询时都是必须要掌握的。

单表查询

单表查询是所有查询中的中间状态,即使是多个表的复杂查询,在进行各种连接后最终都能够被抽象成单表查询。所以先从单表查询开始。

选择列的子集

根据上面数据子集的说法,选择列是通过在SELECT语句后面添加所要选择的列名实现的。

SELECT NAME FROM USERS;

选择行的子集

选择行的子集,是在SQL语句的WHERE子句后面加上相应的限制条件。当WHERE子句后面的表达式为【真/true】时,也就是满足所谓的【条件】时,返回相应的行的子集。

WHERE子句后面的运算符分为两类,分别是比较运算符和逻辑运算符。

比较运算符是将两个相同类型的数据进行比较,进而返回布尔类型(boolean)的运算符。在SQL中,比较运算符一共有六种,分别是等于(=)、小于(<)、小于或等于(<=)、大于或等于(>=)以及不等于(<>)。其中,小于或等于和大于或等于可以看成是比较运算符和逻辑运算符的结合体。

SELECT NAME FROM USERS WHERE AGE >= 18;

逻辑运算符是将两个布尔类型进行连接,并返回一个新的布尔类型的运算符。在SQL中,逻辑运算符通常是将比较运算符返回的布尔类型相连接以最终确定WHERE子句后面满足条件的真假。逻辑运算符一共有三种,分别是与(AND)、或(OR)和非(NOT)。其中,非运算符可以看作是特殊的比较运算符。

SELECT NAME FROM USERS WHERE AGE > 18 AND AGE < 60;

另外,这几种运算符是有优先级的,优先级由大到小排列,是比较运算符>于逻辑运算符(AND)>或逻辑运算符(OR)。当然,也可以通过括号运算符来改变优先级,括号运算符的优先级最高。

1+1≠2的问题

假定USERS表中存在一个SEX(性别)字段,我们一般可能会认为,这个世界不是男人就是女人,因此SEX字段就只能有male和female两种值。

SELECT * FROM USERS WHERE SEX = 'male' AND SEX = 'female';

但是当我们执行上面的SQL时发现获取的并不是USERS表中的所有记录。这是因为,在实际的场景中,有一些用户在录入表单的时候可能不会填写SEX字段,因此SEX字段还会有第三个值:NULL。因此我们需要加入SQL语句中提供的NULL判断条件来获取表中的所有记录。

SELECT * FROM USERS WHERE SEX = 'male' AND SEX = 'female' AND SEX IS NULL;

当然了,实际场景中SEX(性别)一般会被设计为布尔类型,并提供默认值。

排序结果

上面的那些方法都是关于取出数据,而下面是关于将取出的子集进行排序。SQL通过ORDER BY子句来进行排序,ORDER BY子句必须是SQL查询语句的最后一个子句,也就是说,在ORDER BY子句之后,不允许再添加任何的子句了。

ORDER BY子句分为升序(ASC)和降序(DESC)。如果不指定升序或者降序,则默认为升序(由小到大),而ORDER BY是根据排序依据的数据类型来决定的排列的先后顺序的,分别有3种数据类型可以进行排序:字符、数字和时间日期。其中,字符按照字母表进行排序,数字根据数字大小排序,时间日期根据时间的先后进行排序。

SELECT * FROM USERS ORDER BY AGE DESC;

上面的语句即按AGE(年龄)对USERS表中的记录进行降序排序。

聚合函数

聚合的意思就是按照一定的条件进行分组,SQL通过GROUP BY子句来进行分组,通过分组并配合聚合函数来达到聚合统计的目的。另外还提供有HAVING子句与GROUP BY子句联合使用,作用是分组后对数据的筛选/过滤,优先级低于WHERE子句。

SELECT AREA, AVG(AGE) FROM USERS GROUP BY AREA HAVING AVG(AGE) > 18;

上面的语句即按AREA(地区)对USERS表中的记录求平均AGE(年龄),且平均年龄大于18岁,简单描述,就是求USERS表中平均年龄大于18岁的地区。

多表连接查询

在关系数据库中,一个查询往往会涉及多个表,因为很少有数据库只有一个表,而如果大多数查询只涉及到一个表的话,那么那个表也往往低于第三范式,存在大量冗余和异常。因此,连接(JOIN)就是一种把多个表连接成一个表的重要手段。

笛卡尔积

笛卡尔积在SQL中的实现方式即是交叉连接(CROSS JOIN)。所有连接方式都会先生成临时笛卡尔积表,笛卡尔积是关系代数里的一个概念,表示两个表中的每一行数据任意组合。在实际应用中,笛卡尔积本身大多没有什么实际用处,只有在两个表连接时加上限制条件,才会有实际意义。

内连接

如果分步骤理解的话,内连接可以看做是先对两个表进行了交叉连接后,再通过加上限制条件(SQL中通过关键字ON)剔除不符合条件的行的子集,得到的结果就是内连接了。

SELECT * FROM A INNER JOIN B ON A.ID = B.ID;

外连接

外连接是以一个表作为主体,通过限制条件(关键字ON)来进行连接。

左外连接(LEFT OUTER JOIN)是将左表作为主体。

SELECT * FROM A LEFT JOIN B ON A.ID = B.ID;

右外连接(RIGHT OUTER JOIN)是将右表作为主体。

SELECT * FROM A RIGHT JOIN B ON A.ID = B.ID;

全外连接(FULL OUTER JOIN)是将左表和右表每行都至少输出一次,可以看作是左外连接和右外连接的结合。

SELECT * FROM A FULL JOIN B ON A.ID = B.ID;

从上面的语句可以看出,使用外连接编写SQL时可以省略OUTER关键字。

自连接

如果说内连接是取两个表之间的交集,那么自连接也可以这么理解(如果有WHERE,没有WHERE的话则是取的两个表所有记录的完整笛卡尔积)。通常理解上是,自连接是一种特殊的内连接,不同在于内连接是使用ON关键字做限制条件,自连接则是通过WHETE子句来限制记录的获取。

SELECT * FROM A, B WHERE A.ID = B.ID;

交叉连接

交叉连接和没有WHERE条件限制的自连接获取的记录结果是一样的,它们都返回两个表所有记录的完整笛卡尔积。

SELECT * FROM A CROSS JOIN B;

多表连接查询的总结

上面说的连接都是两个表进行连接,而多个表连接实际上可以看成是对N个表进行N-1次双表连接;多个表连接查询之后也可以看作是一个整体,即看成对一个单表进行查询操作。这样分析的话,会让复杂的问题简单化,再困难的问题也能迎刃而解。

"假如人生是一场未知目的地的旅行,我们只是一味地狂奔,却忘记了旅行的意义。"

sql查询入门的更多相关文章

  1. SQL查询入门(下篇)

    SQL查询入门(下篇)   文章转自:http://www.cnblogs.com/CareySon/archive/2011/05/18/2049727.html 引言 在前两篇文章中,对于单表查询 ...

  2. [转]sql语句中出现笛卡尔乘积 SQL查询入门篇

    本篇文章中,主要说明SQL中的各种连接以及使用范围,以及更进一步的解释关系代数法和关系演算法对在同一条查询的不同思路. 多表连接简介 在关系数据库中,一个查询往往会涉及多个表,因为很少有数据库只有一个 ...

  3. sql语句中出现笛卡尔乘积 SQL查询入门篇

    2014-12-29  凡尘工作室   阅 34985  转 95 本篇文章中,主要说明SQL中的各种连接以及使用范围,以及更进一步的解释关系代数法和关系演算法对在同一条查询的不同思路. 多表连接简介 ...

  4. 浅谈SQL优化入门:1、SQL查询语句的执行顺序

    1.SQL查询语句的执行顺序 (7) SELECT (8) DISTINCT <select_list> (1) FROM <left_table> (3) <join_ ...

  5. 【数据库】数据库入门(四): SQL查询 - SELETE的进阶使用

    集合操作常用的集合操作主要有三种:UNION(联合集).INTERSECT(交叉集).EXCEPT(求差集).以上三种集合的操作都是直接作用在两个或者多个 SQL 查询语句之间,将所有的元组按照特定的 ...

  6. SQL 存储过程入门(事务)(四)

    SQL 存储过程入门(事务)(四)   本篇我们来讲一下事务处理技术. 为什么要使用事务呢,事务有什么用呢,举个例子. 假设我们现在有个业务,当做成功某件事情的时候要向2张表中插入数据,A表,B表,我 ...

  7. 浅谈SQL优化入门:3、利用索引

    0.写在前面的话 关于索引的内容本来是想写的,大概收集了下资料,发现并没有想象中的简单,又不想总结了,纠结了一下,决定就大概写点浅显的,好吧,就是懒,先挖个浅坑,以后再挖深一点.最基本的使用很简单,直 ...

  8. 1 小时 SQL 极速入门(三)——分析函数

    1 小时 SQL 极速入门 前面两篇我们从 SQL 的最基础语法讲起,到表联结多表查询. 大家可以点击链接查看 1 小时 SQL 极速入门(一) 1 小时 SQL 极速入门(二) 今天我们讲一些在做报 ...

  9. Oracle+PL+SQL从入门到精通.丁士锋.清华大学出版社.2012

    \t第1篇 pl/sql开发入门第1章 oracle 11g数据库系统1.1 关系型数据库系统介绍1.1.1 什么是关系型数据模型1.1.2 数据库系统范式1.1.3 关系型数据库管理系统1.1.4 ...

随机推荐

  1. 《Maven实战》读书笔记

    一.Maven使用入门 POM(Project Object Model,项目对象模型),定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等等 二.坐标和依赖 1.何为Maven坐标 Mave ...

  2. Linux版本号的数值含义

    Linux内核版本有两种:稳定版和开发版 ,Linux内核版本号由3组数字组成:第一个组数字.第二组数字.第三组数字.第一个组数字:目前发布的内核主版本.第二个组数字:偶数表示稳定版本:奇数表示开发中 ...

  3. 数据结构与算法(C/C++版)【数组】

    第五章<数组> 一.概念 根据数组中存储的数据元素之间的逻辑关系,可以将数组分为 : 一维数组.二维数组.….n维数组.n维数组中,维数 n 的判断依据是:根据数组中为确定元素所在位置使用 ...

  4. python import cv2异常(dll load fail / windows server 2008)

    最近服务器迁移,从得win7系统迁移到云服务器器上的windows server2008系统,迁移过程中安装Python的opencv一直出错,不管是用whl安装或者是在线pip安装都报错,尝试打包成 ...

  5. 【网络安全】给你讲清楚什么是XSS攻击

    给你讲清楚什么是XSS攻击 1. 什么是XSS攻击 跨站脚本攻击(Cross Site Scripting)本来的缩写为CSS,为了与层叠样式表(Cascading Style Sheets,CSS) ...

  6. BERT论文解读

    本文尽量贴合BERT的原论文,但考虑到要易于理解,所以并非逐句翻译,而是根据笔者的个人理解进行翻译,其中有一些论文没有解释清楚或者笔者未能深入理解的地方,都有放出原文,如有不当之处,请各位多多包含,并 ...

  7. scalikejdbc 学习笔记(2)

    使用scalikejdbc config (src\main\resources) # MySQL(dev) dev.db.default.driver="com.mysql.jdbc.Dr ...

  8. 快学Scala 第四课 (多维数组,与Java集合的互操作)

    Scala二维数组的定义: val arr2 = Array.ofDim[String](2, 2) arr2(0)(0) = "aa" arr2(1)(0) = "bb ...

  9. linux下安装配置go语言环境

    1,golang中国下载go源码  http://www.golangtc.com/download  请对应系统版本号,linux-amd64.tar.gz为64位系统(推荐) ,linux-386 ...

  10. windows服务器多端口Redis安装步骤

    1.从官网获取最新稳定版redis文件.按端口号复制多个文件,比如6379和6380端口的文件包, 修改各自Conf文件的port号,分别为6379和6380.然后重命名为redis6379.conf ...