高级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操作符进行通配搜索,以便对数据进行复杂过滤。

相关推荐
gavin_gxh几秒前
ORACLE 删除archivelog日志
数据库·oracle
一叶飘零_sweeeet3 分钟前
MongoDB 基础与应用
数据库·mongodb
猿小喵19 分钟前
DBA之路,始于足下
数据库·dba
tyler_download28 分钟前
golang 实现比特币内核:实现基于椭圆曲线的数字签名和验证
开发语言·数据库·golang
weixin_449310841 小时前
高效集成:聚水潭采购数据同步到MySQL
android·数据库·mysql
floret*1 小时前
HiveSQL面试题
hive·sql
Cachel wood2 小时前
Github配置ssh key原理及操作步骤
运维·开发语言·数据库·windows·postgresql·ssh·github
standxy2 小时前
如何将钉钉新收款单数据高效集成到MySQL
数据库·mysql·钉钉
zybsjn2 小时前
数据库索引创建的最佳实践:规范与优化指南
sql
Narutolxy3 小时前
MySQL 权限困境:从权限丢失到权限重生的完整解决方案20241108
数据库·mysql