[数据库] SQL 语法之基础篇
一、什么是 SQL ?
SQL 是 Structured Query Language(结构化查询语言)的缩写,是一种专门用来与数据库沟通的语言。与其他语言(如英语或 C、C++、Java 这样的编程语言)不一样,SQL 中只有很少的词,这是有意而为的。设计 SQL 的目的是很好地完成一项任务 一 提供一种从数据库中读写数据的简单有效的方法。
SQL 有如下的优点:
- SQL 不是某个特定数据库供应商专有的语言。几乎所有重要的 DBMS 都支持 SQL ,所以学习此语言使你几乎能与所有数据库打交道;
- SQL 简单易学。它的语句全都是由有很强描述性的英语单词组成,而且这些单词的数目不多;
- SQL 虽然看上去很简单,但实际上是一种强有力的语言,灵活使用其语言元素,可以进行非常复杂和高级的数据库操作。
二、创建、更新和删除表
下面先讲讲授创建、更改和删除表的 SQL 语法。
2.1 创建表
用程序创建表,可以使用 SQL 的 CREATE TABLE 语句。下面的 SQL 语句创建本文中所用的 Products 表:
CREATE TABLE Products(
prod id CHAR(10) NOT NULL,
vend id CHAR(10) NOT NULL,
prod name CHAR(254) NOT NULL,
prod price DECIMAL(8,2) NOT NULL DEFAULT 3,
proddesc VARCHAR(1000) NULL
);
从上面的例子可以看到,表名紧跟 CREATE TABLE 关键字。实际的表定义(所有列)括在圆括号之中,各列之间用逗号分隔。有一列的描述增加了 DEFAULT 3,指示 DBMS,如果不给出价格则使用价格 3。
2.2 更新表
更新表定义,可以使用 ALTER TABLE 语句。因为给已有表增加列可能是所有 DBMS 都支持的唯一操作,所以我们举个这样的例子:
ALTER TABLE Vendors ADD vend_phone CHAR(20);
这条语句给 Vendors 表增加一个名为 vend_phone 的列,其数据类型为 CHAR。删除列,就使用DROP COLUMN col_name
即可。
2.3 删除表
删除表(删除整个表而不是其内容)非常简单,如下所示:
DROP TABLE CustCopy;
这条语句删除 CustCopy 表。删除表没有确认,也不能撤销,执行这条语句将永久删除该表。
使用关系规则防止意外删除 许多 DBMS 允许强制实施有关规则,防止删除与其他表相关联的表。在实施这些规则时,如果对某个表发布一条 DROP TABLE 语句,且该表是某个关系的组成部分,则 DBMS 将阻止这条语句执行,直到该关系被删除为止。 |
三、插入数据
下面介绍如何利用 SQL 的 INSERT 语句将数据插入表中。
3.1 数据插入
把数据插入表中的最简单方法是使用基本的 INSERT 语法,它要求指定表名和插入到新行中的值。下面举一个例子:
INSERT INTO Customers VALUES('1000000006', 'Toy Land', '123 Any Street', 'New York', 'NY', '11111', 'USA', NULL, NULL);
这个例子将一个新顾客插入到 Customers 表中。存储到表中每一列的数据在 VALUES 子句中给出,必须给每一列提供一个值。如果某列没有值,如上面的 cust_contact 和 cust_email 列,则应该使用 NULL 值(假定表允许对该列指定空值)。各列必须以它们在表定义中出现的次序填充。
虽然这种语法很简单,但并不安全,应该尽量避免使用。上面的 SQL 语句高度依赖于表中列的定义次序,还依赖于其容易获得的次序信息。即使可以得到这种次序信息,也不能保证各列在下一次表结构变动后保持完全相同的次序。因此,编写依赖于特定列次序的 SQL 语句是很不安全的,这样做迟早会出问题。
编写 INSERT 语句的更安全(不过更烦琐)的方法如下:
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES('1000000006', 'Toy Land', '123 Any Street', 'New York', 'NY', '11111', 'USA', NULL, NULL);
这个例子与前一个 INSERT 语句的工作完全相同,但在表名后的括号里明确给出了列名。在插入行时,DBMS 将用 VALUES 列表中的相应值填入列表中的对应项。因为提供了列名,VALUES 必须以其指定的次序匹配指定的列名,不一定按各列出现在表中的实际次序。其优点是,即使表的结构改变,这条 INSERT 语句仍然能正确工作。
3.2 从一个表复制到另一个表
要将一个表的内容复制到一个全新的表(运行中创建的表),可以使用 SELECT INTO 语句。MariaDB、MySQL、Oracle、PostgreSQL 和 SQLite 使用的语法如下:
CREATE TABLE CustCopy AS SELECT * FROM Customers;
这条 SELECT 语句创建一个名为 CustCopy 的新表,并把 Customers 表的整个内容复制到新表中。因为这里使用的是 SELECT *,所以将在 CustCopy 表中创建(并填充)与 Customers 表的每一列相同的列。要想只复制部分的列,可以明确给出列名,而不是使用 * 通配符。
四、更新和删除数据
下面介绍如何利用 UPDATE 和 DELETE 语句进一步操作表数据。
4.1 更新数据
更新(修改)表中的数据,可以使用 UPDATE 语句。例子如下:
UPDATE Customers SET cust_contact = 'Sam Roberts', cust_email = 'sam@toyland.cxx' WHERE cust_id = '1000000006';
UPDATE 语句以 WHERE 子句结束,它告诉 DBMS 更新哪一行。没有 WHERE 子句,DBMS 将会用这个电子邮件地址更新 Customers 表中的所有行,这不是我们希望的。
4.2 删除数据
从一个表中删除数据,使用 DELETE 语句。下面的语句从 Customers 表中删除一行:
DELETE FROM Customers WHERE cust_id = '1000000006';
这条语句很容易理解。DELETE FROM 要求指定从中删除数据的表名,WHERE 子句过滤要删除的行。在这个例子中,只删除顾客 1000000006。如果省略 WHERE 子句,它将删除表中每个顾客。
五、检索数据
下面介绍如何使用 SELECT 语句从表中检索一个或多个数据列。
5.1 SELECT 语句
正如上面所述,SQL语句是由简单的英语单词构成的。这些单词称为关键字,每个 SQL 语句都是由一个或多个关键字构成的。最经常使用的 SQL 语句大概就是 SELECT 语句了。它的用途是从一个或多个表中检索信息。
关键字(keyword) 作为 SQL 组成部分的保留字。关键字不能用作表或列的名字。附录E列出了某些经常使用的保留字。 |
为了使用 SELECT 检索表数据,必须至少给出两条信息一想选择什么,以及从什么地方选择。
5.2 检索单个列
我们将从简单的 SELECT 语句讲起,语句如下所示:
SELECT prod_name FROM Products;
上述语句利用 SELECT 语句从 Products 表中检索一个名为 prod_name 的列。所需的列名写在 SELECT 关键字之后,FROM 关键字指出从哪个表中检索数据。
提示1: SQL 语句和大小写
请注意, SQL 语句不区分大小写,因此 SELECT 与 SELECT 是相同的。同样,写成 SELECT 也没有关系。许多 SQL 开发人员喜欢对 SQL 关键字使用大写,而对列名和表名使用小写,这样做使代码更易于阅读和调试。不过,一定要认识到虽然 SQL 是不区分大小写的,但是表名、列名和值可能有所不同(这有赖于具体的DBMS及其如何配置)。 提示2:使用空格 在处理 SQL 语句时,其中所有空格都被忽略。 SQL 语句可以写成长长的一行,也可以分写在多行。多数 SQL 开发人员认为,将 SQL 语句分成多行更容易阅读和调试。 |
5.3 检索多个行
要想从一个表中检索多个列,仍然使用相同的 SELECT 语句。唯一的不同是必须在 SELECT 关键字后给出多个列名,列名之间必须以逗号分隔。
SELECT prod_id, prod_name, prod_price FROM Products;
这条语句使用 SELECT 语句从表 Products 中选择多个数据。在这个例子中,指定了 3 个列名,列名之间用逗号分隔。
5.4 检索所有列
除了指定所需的列外(如上所述,一个或多个列),SELECT 语句还可以检索所有的列而不必逐个列出它们。在实际列名的位置使用星号(*)通配符可以做到这点,如下所示:
SELECT * FROM Products;
如果给定一个通配符(*),则返回表中所有列。列的顺序一般是列在表定义中出现的物理顺序,但并不总是如此。
5.5 检索不同的值
如前所述,SELECT 语句返回所有匹配的行。但是,如果你不希望每个值每次都出现,该怎么办呢?办法就是使用 DISTINCT 关键字,顾名思义,它指示数据库只返回不同的值。
SELECT DISTINCT vend_id FROM Products;
SELECT DISTINCT vend_id 告诉 DBMS 只返回不同(具有唯一性)的 vend_id 行。如果使用 DISTINCT 关键字,它必须直接放在列名的前面。
警告:不能部分使用 DISTINCT DISTINCT 关键字作用于所有的列,不仅仅是跟在其后的那一列。例如,你指定 SELECT DISTINCT vend_id,prod_price,除非指定的两列完全相同,否则所有的行都会被检索出来。 |
5.6 限制结果
SELECT 语句返回指定表中所有匹配的行,很可能是每一行。如果你只想返回第一行或者一定数量的行,该怎么办呢?这是可行的,然而遗憾的是,各种数据库中的 SQL 实现并不相同。
如果你使用 My SQL 、MariaDB、Postgre SQL 或者 SQL ite,需要使用 LIMIT子句,像这样:
SELECT prod_name FROM Products LIMIT 5;
上述代码使用 SELECT 语句来检索单独的一列数据。LIMIT 5 指示 My SQL 等 DBMS 返回不超过 5 行的数据。
为了得到后面的 5 行数据,需要指定从哪儿开始以及检索的行数,像这样:
SELECT prod_name FROM Products LIMIT 5 OFFSET 5;
LIMIT 5 OFFSET 5
指示 My SQL 等 DBMS 返回从第 5 行起的 5 行数据。第一个数字是指从哪儿开始,第二个数字是检索的行数。
警告:第 0 行
第一个被检索的行是第 0 行,而不是第 1 行。因此,LIMIT 1 OFFSET 1 会检索第 2 行,而不是第 1 行。 提示:My SQL 和MariaDB快捷键 My SQL 和MariaDB支持简化版的LIMIT 4 OFFSET 3语句,即LIMIT 3,4。使用这个语法,之前的值对应 LIMIT,之后的值对应 OFFSET。 |
5.7 使用注释
我们先来看行内注释:
SELECT prod_name FROM Products; --这是一条注释
注释使用--
(两个连字符)嵌在行内,之后的文本就是注释。
你也可以进行多行注释,注释可以在脚本的任何位置停止和开始。
/* SELECT prod_name, vend_id
FROM Products; */
SELECT prod_name FROM Products;
注释从/*
开始,到*/
结束,之间的任何内容都是注释。
六、排序检索数据
下面讲授如何使用 SELECT 语句的 ORDER BY 子句,根据需要排序检索出的数据。
6.1 排序数据
为了明确地排序用 SELECT 语句检索出的数据,可使用 ORDER BY 子句。ORDER BY 子句取一个或多个列的名字,据此对输出进行排序。请看下面的例子:
SELECT prod_name FROM Products ORDER BY prod_name;
ORDER BY 子句,指示 DBMS 软件对 prod_name 列以字母顺序排序数据。
注意:ORDER BY 子句的位置 在指定一条 ORDER BY 子句时,应该保证它是 SELECT 语句中最后一条子句。如果它不是最后的子句,将会出现错误消息。 |
6.2 按多个列排序
下面的代码检索 3 个列,并按其中两个列对结果进行排序 一 首先按价格,然后按名称排序。
SELECT prod_id, prod_price, prod_name FROM Products ORDER BY prod_price, prod_name;
对于上述例子中的输出,仅在多个行具有相同的 prod_price 值时才对产品按 prod_name 进行排序。如果 prod_price 列中所有的值都是唯一的,则不会按 prod_name 排序。(先对 prod_price 排序,再对 prod_name 排序)
6.3 按列位置排序
除了能用列名指出排序顺序外,ORDER BY 还支持按相对列位置进行排序。为理解这一内容,我们来看个例子:
SELECT prod_id, prod_price, prod_name FROM Products ORDER BY 2, 3;
SELECT 清单中指定的是选择列的相对位置而不是列名。ORDER BY 2 表示按 SELECT 清单中的第二个列 prod_name 进行排序。ORDER BY 2, 3 表示先按 prod_price,再按 prod_name 进行排序。
6.4 指定排序方向
数据排序不限于升序排序(从 A 到 Z),这只是默认的排序顺序。还可以使用 ORDER BY 子句进行降序(从 Z 到 A )排序。为了进行降序排序,必须 指定 DESC 关键字。例子如下:
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 关键字。 |
七、过滤数据
下面将讲授如何使用 SELECT 语句的 WHERE 子句指定搜索条件。
7.1 使用 WHERE 子句
在 SELECT 语句中,数据根据 WHERE 子句中指定的搜索条件进行过滤。WHERE 子句在表名(FROM 子句)之后给出,如下所示:
SELECT prod_name, prod_price FROM Products WHERE prod_price = 3.49;
这条语句从 products 表中检索两个列,但不返回所有行,只返回 prod_price 值为 3.49 的行。
7.2 WHERE 子句操作符
SQL 支持下表列出的所有条件操作符。
操作符 | 说明 |
---|---|
= | 等于 |
!= | 不等于 |
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
BETWEEN | 在指定的两个值之间 |
IS NULL | 为NULL值 |
1. 范围内检查
要检查某个范围的值,可以使用 BETWEEN 操作符。其语法与其他 WHERE 子句的操作符稍有不同,因为它需要两个值,即范围的开始值和结束值。下面的例子说明如何使用 BETWEEN 操作符,它检索价格在 5 美元和 10 美元之间的所有产品:
SELECT prod_name, prod_price FROM Products WHERE prod_price BETWEEN 5 AND 10;
从这个例子可以看到,在使用 BETWEEN 时,必须指定两个值——所需范围的低端值和高端值。这两个值必须用 AND 关键字分隔。
2. 空值检查
确定值是否为 NULL,不能简单地检查是否 =NULL。SELECT 语句有一个特殊的 WHERE 子句,可用来检查具有 NULL 值的列。这个 WHERE 子句就是 IS NULL 子句。其语法如下:
SELECT prod_name FROM Products WHERE prod_price IS NULL;
这条语句返回所有没有价格(空 prod_price 字段,不是价格为 0)的产品。
八、高级数据过滤
下面讲授如何组合 WHERE 子句以建立功能更强、更高级的搜索条件。我们还将学习如何使用 NOT 和 IN 操作符。
8.1 组合 WHERE 子句
第 4 课介绍的所有 WHERE 子句在过滤数据时使用的都是单一的条件。为了进行更强的过滤控制,SQL 允许给出多个 WHERE 子句。这些子句有两种使用方式,即以 AND 子句或 OR 子句的方式使用。
1. AND 操作符
要通过不止一个列进行过滤,可以使用 AND 操作符给 WHERE 子句附加条件。下面的代码给出了一个例子:
SELECT prod_id, prod_price, prod_name FROM Products WHERE vend_id = 'DLL01' AND prod_price <= 4;
此 SQL 语句检索由供应商 DLL01 制造且价格小于等于 4 美元的所有产品的名称和价格。
2. OR 操作符
OR 操作符与 AND 操作符正好相反,它指示 DBMS 检索匹配任一条件的行。事实上,许多 DBMS 在 OR WHERE 子句的第一个条件得到满足的情况下, 就不再计算第二个条件了。例子如下:
SELECT prod_name, prod_price FROM Products WHERE vend_id = 'DLL01' OR vend_id = 'BRS01';
此 SQL 语句检索由任一个指定供应商制造的所有产品的产品名和价格。
8.2 IN操作符
IN 操作符用来指定条件范围,范围中的每个条件都可以进行匹配。IN 取一组由逗号分隔、括在圆括号中的合法值。下面的例子说明了这个操作符:
SELECT prod_name, prod_price FROM Products WHERE vend_id IN ( 'DLL01', 'BRS01' );
此 SELECT 语句检索由供应商 DLL01 和 BRS01 制造的所有产品。IN 操作符后跟由逗号分隔的合法值,这些值必须括在圆括号中。 你可能会猜测 IN 操作符完成了与 OR 相同的功能,恭喜你猜对了!
8.3 NOT操作符
WHERE 子句中的 NOT 操作符有且只有一个功能,那就是否定其后所跟的任何条件。NOT 关键字可以用在要过滤的列前,而不仅是在其后。下面的例子说明了这个操作符:
SELECT prod_name FROM Products WHERE NOT vend_id = 'DLL01';
这里的 NOT 否定跟在其后的条件,因此,DBMS 不是匹配 vend_id 为 DLL01,而是匹配非 DLL01 之外的所有东西。
九、用通配符进行过滤
下面介绍什么是通配符、如何使用通配符以及怎样使用 LIKE 操作符进行通配搜索,以便对数据进行复杂过滤。
1. 百分号(%)通配符
最常使用的通配符是百分号(%)。在搜索串中,% 表示任何字符出现任意次数。例如,为了找出所有以词 Fish 起头的产品,可发布以下 SELECT 语句:
SELECT prod_id, prod_name FROM Products WHERE prod_name LIKE 'Fish%';
此例子使用了搜索模式 'Fish%’。在执行这条子句时,将检索任意以 Fish 起头的词。% 告诉 DBMS 接受 Fish 之后的任意字符,不管它有多少字符。
2. 下划线(_)通配符
另一个有用的通配符是下划线(_)。下划线的用途与 % —样,但它只匹配单个字符,而不是多个字符。例子如下:
SELECT prod_id,prod_name FROM Products WHERE prod_name LIKE '__ inch teddy bear';
这个 WHERE 子句中的搜索模式给出了后面跟有文本的两个通配符。
3. 方括号([])通配符
方括号([])通配符用来指定一个字符集,它必须匹配指定位置(通配符的位置)的一个字符。例如,找出所有名字以 J 或 M 起头的联系人,可进行如下查询:
SELECT cust_contact FROM Customers WHERE cust_contact LIKE '[JM]%';
这一搜索模式使用了两个不同的通配符。[JM] 匹配任何以方括号中字母开头的联系人名,它也只能匹配单个字符。[JM] 之后的 % 通配符匹配第一个字符之后的任意数目的字符,返回所需结果。
参考:
《SQL 必知必会》
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!