高级SQL语句

1、检索数据

1.1、检索不同的值:DISTINCT关键字

sql 复制代码
    SELECT DISTINCT vend_id FROM Products;

SELECT DISTINCT vend_id告诉DBMS只返回不同(具有唯一性)的vend_id行。

**注意:**不能部分使用DISTINCT。DISTINCT关键字作用于所有的列,不仅仅是跟在其后的那一列。

1.2、限制结果

SELECT语句返回指定表中所有匹配的行,很可能是每一行。如果你只想返回第一行或者一定数量的行,这是可行的,然而遗憾的是,各种数据库中的这一SQL实现并不相同。

1、在SQL Server中使用SELECT时,可以用TOP关键字来限制最多返回多少行,如下所示:

sql 复制代码
    SELECT TOP 5 prod_name
    FROM Products;

上面代码使用SELECT TOP 5语句,只检索前5行数据。

2、如果你使用的是DB2,就得使用下面这样的DB2特有的SQL语句:

sql 复制代码
    SELECT prod_name
    FROM Products
    FETCH FIRST 5 ROWS ONLY;

3、如果你使用Oracle,需要基于ROWNUM(行计数器)来计算行,像这样:

sql 复制代码
    SELECT prod_name
    FROM Products
    WHERE ROWNUM <=5;

4、如果你使用MySQL、MariaDB、PostgreSQL或者SQLite,需要使用LIMIT子句,像这样:

sql 复制代码
    SELECT prod_name
    FROM Products
    LIMIT 5;

上述代码使用SELECT语句来检索单独的一列数据。LIMIT 5指示MySQL等DBMS返回不超过5行的数据。这个语句的输出参见下面的代码。

为了得到后面的5行数据,需要指定从哪儿开始以及检索的行数,像这样:

sql 复制代码
    SELECT prod_name
    FROM Products
    LIMIT 5 OFFSET 5;

LIMIT 5 OFFSET 5指示MySQL等DBMS返回从第5行起的5行数据。第一个数字是检索的行数,第二个数字是指从哪儿开始。

2、排序检索数据

关系数据库设计理论认为,如果不明确规定排序顺序,则不应该假定检索出的数据的顺序有任何意义。

子句(clause):SQL语句由子句构成,有些子句是必需的,有些则是可选的。一个子句通常由一个关键字加上所提供的数据组成。

2.1、排序数据

为了明确地排序用SELECT语句检索出的数据,可使用ORDER BY子句。ORDER BY子句取一个或多个列的名字,据此对输出进行排序。请看下面的例子:

sql 复制代码
    SELECT prod_name
    FROM Products
    ORDER BY prod_name;

注意:ORDER BY子句的位置在指定一条ORDER BY子句时,应该保证它是SELECT语句中最后一条子句。如果它不是最后的子句,将会出错。

2.2、按多个列排序

要按多个列排序,只须指定这些列名,列名之间用逗号分开即可(就像选择多个列时那样)。

下面的代码检索3个列,并按其中两个列对结果进行排序------首先按价格,然后按名称排序。

sql 复制代码
    SELECT prod_id, prod_price, prod_name
    FROM Products
    ORDER BY prod_price, prod_name;

重要的是理解在按多个列排序时,排序的顺序完全按规定进行。换句话说,对于上述例子中的输出,仅在多个行具有相同的prod_price值时才对产品按prod_name进行排序。如果prod_price列中所有的值都是唯一的,则不会按prod_name排序。

2.3、按列位置排序

除了能用列名指出排序顺序外,ORDER BY还支持按相对列位置进行排序。为理解这一内容,我们来看个例子:

sql 复制代码
    SELECT prod_id, prod_price, prod_name
    FROM Products
    ORDER BY 2, 3;

可以看到,这里的输出与上面的查询相同,不同之处在于ORDER BY子句。SELECT清单中指定的是选择列的相对位置而不是列名。ORDER BY 2表示按SELECT清单中的第二个列prod_price进行排序。ORDER BY 2, 3表示先按prod_price,再按prod_name进行排序。

这一技术的主要好处在于不用重新输入列名。但它也有缺点。首先,不明确给出列名有可能造成错用列名排序。其次,在对SELECT清单进行更改时容易错误地对数据进行排序(忘记对ORDER BY子句做相应的改动)。最后,如果进行排序的列不在SELECT清单中,显然不能使用这项技术。

提示:按非选择列排序显然,当根据不出现在SELECT清单中的列进行排序时,不能采用这项技术。但是,如果有必要,可以混合使用实际列名和相对列位置。

2.4、指定排序方向

数据排序不限于升序排序(从A到Z),这只是默认的排序顺序。还可以使用ORDER BY子句进行降序(从Z到A)排序。为了进行降序排序,必须指定DESC关键字。

下面的例子以价格降序来排序产品(最贵的排在最前面):

sql 复制代码
    SELECT prod_id, prod_price, prod_name
    FROM Products
    ORDER BY prod_price DESC;

如果打算用多个列排序,该怎么办?下面的例子以降序排序产品(最贵的在最前面),再加上产品名:

sql 复制代码
    SELECT prod_id, prod_price, prod_name
    FROM Products
    ORDER BY prod_price DESC, prod_name;

DESC关键字只应用到直接位于其前面的列名。在上例中,只对prod_price列指定DESC,对prod_name列不指定。因此,prod_price列以降序排序,而prod_name列(在每个价格内)仍然按标准的升序排序。

警告:在多个列上降序排序如果想在多个列上进行降序排序,必须对每一列指定DESC关键字。

请注意,DESC是DESCENDING的缩写,这两个关键字都可以使用。与DESC相对的是ASC(或ASCENDING),在升序排序时可以指定它。但实际上,ASC没有多大用处,因为升序是默认的(如果既不指定ASC也不指定DESC,则假定为ASC)。

提示:区分大小写和排序顺序在对文本性数据进行排序时,A与a相同吗?a位于B之前,还是Z之后?这些问题不是理论问题,其答案取决于数据库的设置方式。在字典(dictionary)排序顺序中,A被视为与a相同,这是大多数数据库管理系统的默认做法。但是,许多DBMS允许数据库管理员在需要时改变这种行为(如果你的数据库包含大量外语字符,可能必须这样做)。这里的关键问题是,如果确实需要改变这种排序顺序,用简单的ORDER BY子句可能做不到。你必须请求数据库管理员的帮助。

3、过滤数据

3.1、使用WHERE子句

数据库表一般包含大量的数据,很少需要检索表中的所有行。通常只会根据特定操作或报告的需要提取表数据的子集。只检索所需数据需要指定搜索条件(search criteria),搜索条件也称为过滤条件(filter condition)。

在SELECT语句中,数据根据WHERE子句中指定的搜索条件进行过滤。WHERE子句在表名(FROM子句)之后给出,如下所示:

sql 复制代码
    SELECT prod_name, prod_price
    FROM Products
    WHERE prod_price = 3.49;


提示:SQL过滤与应用过滤数据也可以在应用层过滤。为此,SQL的SELECT语句为客户端应用检索出超过实际所需的数据,然后客户端代码对返回数据进行循环,提取出需要的行。通常,这种做法极其不妥。优化数据库后可以更快速有效地对数据进行过滤。而让客户端应用(或开发语言)处理数据库的工作将会极大地影响应用的性能,并且使所创建的应用完全不具备可伸缩性。此外,如果在客户端过滤数据,服务器不得不通过网络发送多余的数据,这将导致网络带宽的浪费。

注意:WHERE子句的位置在同时使用ORDER BY和WHERE子句时,应该让ORDER BY位于WHERE之后,否则将会产生错误。

3.2、WHERE子句操作符

我们在做相等检验时看到了第一个WHERE子句,它确定一个列是否包含指定的值。下表列出的所有条件操作符。

注意:上表中列出的某些操作符是冗余的(如< >与!=相同,!<相当于>=)。并非所有DBMS都支持这些操作符。想确定你的DBMS支持哪些操作符,请参阅相应的文档。

3.2.1、检查单个值

列出所有价格小于10美元的产品。

sql 复制代码
    SELECT prod_name, prod_price
    FROM Products
    WHERE prod_price < 10;

3.2.2、不匹配检查

列出所有不是供应商DLL01制造的产品。

sql 复制代码
    SELECT vend_id, prod_name
    FROM Products
    WHERE vend_id <> 'DLL01';


提示:何时使用引号如果仔细观察上述WHERE子句中的条件,会看到有的值括在单引号内,而有的值未括起来。单引号用来限定字符串。如果将值与字符串类型的列进行比较,就需要限定引号。用来与数值列进行比较的值不用引号。

下面是相同的例子,其中使用!=而不是<>操作符:

sql 复制代码
    SELECT vend_id, prod_name
    FROM Products
    WHERE vend_id != 'DLL01';

注意:是!=还是<>?!=和<>通常可以互换。但是,并非所有DBMS都支持这两种不等于操作符。如果有疑问,请参阅相应的DBMS文档。

3.2.3、范围值检查

要检查某个范围的值,可以使用BETWEEN操作符。其语法与其他WHERE子句的操作符稍有不同,因为它需要两个值,即范围的开始值和结束值。例如,BETWEEN操作符可用来检索价格在5美元和10美元之间的所有产品,或在指定的开始日期和结束日期之间的所有日期。

下面的例子说明如何使用BETWEEN操作符,它检索价格在5美元和10美元之间的所有产品。

sql 复制代码
    SELECT prod_name, prod_price
    FROM Products
    WHERE prod_price BETWEEN 5 AND 10;

从这个例子可以看到,在使用BETWEEN时,必须指定两个值------所需范围的低端值和高端值。这两个值必须用AND关键字分隔。BETWEEN匹配范围中所有的值,包括指定的开始值和结束值。

3.2.4、空值检查

在创建表时,表设计人员可以指定其中的列能否不包含值。在一个列不包含值时,称其包含空值NULL。
NULL无值(no value),它与字段包含0、空字符串或仅仅包含空格不同。

确定值是否为NULL,不能简单地检查是否等于NULL。SELECT语句有一个特殊的WHERE子句,可用来检查具有NULL值的列。这个WHERE子句就是IS NULL子句。其语法如下:

sql 复制代码
    SELECT prod_name
    FROM Products
    WHERE prod_price IS NULL;

这条语句返回所有没有价格(空prod_price字段,不是价格为0)的产品,由于表中没有这样的行,所以没有返回数据。但是,Customers表确实包含具有NULL值的列:如果没有电子邮件地址,则cust_email列将包含NULL值:

sql 复制代码
    SELECT cust_name
    FROM Customers
    WHERE cust_email IS NULL;


注意:NULL和非匹配通过过滤选择不包含指定值的所有行时,你可能希望返回含NULL值的行。但是这做不到。因为NULL比较特殊,所以在进行匹配过滤或非匹配过滤时,不会返回这些结果。

4、高级数据过滤

如何组合WHERE子句以建立功能更强、更高级的搜索条件。我们还将学习如何使用NOT和IN操作符。

4.1、组合WHERE子句

为了进行更强的过滤控制,SQL允许给出多个WHERE子句。这些子句有两种使用方式,即以AND子句或OR子句的方式使用。

操作符(operator)用来联结或改变WHERE子句中的子句的关键字,也称为逻辑操作符(logical operator)。

1、AND操作符

要通过不止一个列进行过滤,可以使用AND操作符给WHERE子句附加条件。下面的代码给出了一个例子:

sql 复制代码
  SELECT prod_id, prod_price, prod_name
  FROM Products
  WHERE vend_id = 'DLL01' AND prod_price <= 4;

AND用在WHERE子句中的关键字,用来指示检索满足所有给定条件的行。

2、OR操作符

OR操作符与AND操作符正好相反,它指示DBMS检索匹配任一条件的行。事实上,许多DBMS在OR WHERE子句的第一个条件得到满足的情况下,就不再计算第二个条件了(在第一个条件满足时,不管第二个条件是否满足,相应的行都将被检索出来)。

sql 复制代码
    SELECT prod_id, prod_price, prod_name
    FROM Products
    WHERE vend_id = 'DLL01' OR vend_id = 'BRS01';

此SQL语句检索由任一个指定供应商制造的所有产品的产品名和价格。OR操作符告诉DBMS匹配任一条件而不是同时匹配两个条件。

3、求值顺序

WHERE子句可以包含任意数目的AND和OR操作符。允许两者结合以进行复杂、高级的过滤。

但是,组合AND和OR会带来了一个有趣的问题。为了说明这个问题,来看一个例子。假如需要列出价格为10美元及以上,且由DLL01或BRS01制造的所有产品。下面的SELECT语句使用组合的AND和OR操作符建立了一个WHERE子句:

sql 复制代码
    SELECT prod_name, prod_price
    FROM Products
    WHERE vend_id = 'DLL01' OR vend_id = 'BRS01'
          AND prod_price >= 10;

请看上面的结果。返回的行中有4行价格小于10美元,显然,返回的行未按预期的进行过滤。为什么会这样呢?原因在于求值的顺序。SQL(像多数语言一样)在处理OR操作符前,优先处理AND操作符。当SQL看到上述WHERE子句时,它理解为:由供应商BRS01制造的价格为10美元以上的所有产品,以及由供应商DLL01制造的所有产品,而不管其价格如何。换句话说,由于AND在求值过程中优先级更高,操作符被错误地组合了。此问题的解决方法是使用圆括号对操作符进行明确分组。请看下面的SELECT语句及输出:

sql 复制代码
    SELECT prod_name, prod_price
    FROM Products
    WHERE (vend_id = 'DLL01' OR vend_id = 'BRS01')
          AND prod_price >= 10;

这条SELECT语句与前一条的唯一差别是,将前两个条件用圆括号括了起来。因为圆括号具有比AND或OR操作符更高的优先级,所以DBMS首先过滤圆括号内的OR条件。这时,SQL语句变成了选择由供应商DLL01或BRS01制造的且价格在10美元及以上的所有产品,这正是我们希望的结果。

提示:在WHERE子句中使用圆括号任何时候使用具有AND和OR操作符的WHERE子句,都应该使用圆括号明确地分组操作符。不要过分依赖默认求值顺序,即使它确实如你希望的那样。使用圆括号没有什么坏处,它能消除歧义。

4.2、IN操作符

IN操作符用来指定条件范围,范围中的每个条件都可以进行匹配。IN取一组由逗号分隔、括在圆括号中的合法值。下面的例子说明了这个操作符。

sql 复制代码
    SELECT prod_name, prod_price
    FROM Products
    WHERE vend_id  IN ('DLL01','BRS01')
    ORDER BY prod_name;

此SELECT语句检索由供应商DLL01和BRS01制造的所有产品。IN操作符后跟由逗号分隔的合法值,这些值必须括在圆括号中。

你可能会猜测IN操作符完成了与OR相同的功能,恭喜你猜对了!下面的SQL语句完成与上面的例子相同的工作。

sql 复制代码
    SELECT prod_name, prod_price
    FROM Products
    WHERE vend_id = 'DLL01' OR vend_id = 'BRS01'
    ORDER BY prod_name;

为什么要使用IN操作符?其优点如下。

  • 在有很多合法选项时,IN操作符的语法更清楚,更直观。
  • 在与其他AND和OR操作符组合使用IN时,求值顺序更容易管理。
  • IN操作符一般比一组OR操作符执行得更快(在上面这个合法选项很少的例子中,你看不出性能差异)。
  • IN的最大优点是可以包含其他SELECT语句,能够更动态地建立WHERE子句。

INWHERE子句中用来指定要匹配值的清单的关键字,功能与OR相当。

4.3、NOT操作符

WHERE子句中的NOT操作符有且只有一个功能,那就是否定其后所跟的任何条件。因为NOT从不单独使用(它总是与其他操作符一起使用),所以它的语法与其他操作符有所不同。NOT关键字可以用在要过滤的列前,而不仅是在其后。

NOT:WHERE子句中用来否定其后条件的关键字。

下面的例子说明NOT的用法。为了列出除DLL01之外的所有供应商制造的产品,可编写如下的代码。

sql 复制代码
    SELECT prod_name
    FROM Products
    WHERE NOT vend_id = 'DLL01'
    ORDER BY prod_name;

这里的NOT否定跟在其后的条件,因此,DBMS不是匹配vend_id为DLL01,而是匹配非DLL01之外的所有东西。

上面的例子也可以使用<>操作符来完成,如下所示。

sql 复制代码
    SELECT prod_name
    FROM Products
    WHERE vend_id  <> 'DLL01'
    ORDER BY prod_name;

为什么使用NOT?对于这里的这种简单的WHERE子句,使用NOT确实没有什么优势。但在更复杂的子句中,NOT是非常有用的。例如,在与IN操作符联合使用时,NOT可以非常简单地找出与条件列表不匹配的行。

说明:MariaDB中的NOTMariaDB支持使用NOT否定IN、BETWEEN和EXISTS子句。大多数DBMS允许使用NOT否定任何条件。

5、用通配符进行过滤

什么是通配符、如何使用通配符,以及怎样使用LIKE操作符进行通配搜索,以便对数据进行复杂过滤。

相关推荐
Karoku06617 分钟前
【企业级分布式系统】ELK优化
运维·服务器·数据库·elk·elasticsearch
莫叫石榴姐31 分钟前
数据科学与SQL:组距分组分析 | 区间分布问题
大数据·人工智能·sql·深度学习·算法·机器学习·数据挖掘
小技与小术1 小时前
数据库表设计范式
数据库·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作
运维·服务器·数据库·sql·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验九 触发器
数据库·sql·mysql·oracle·实验报告
Loganer2 小时前
MongoDB分片集群搭建
数据库·mongodb
LKID体2 小时前
Python操作neo4j库py2neo使用之创建和查询(二)
数据库·python·neo4j
刘大浪2 小时前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
一只爱撸猫的程序猿2 小时前
简单实现一个系统升级过程中的数据平滑迁移的场景实例
数据库·spring boot·程序员
无敌岩雀2 小时前
MySQL中的索引
数据库·mysql