结构化查询语言/数据查询语言
数据查询语言用于从数据库中提取数据。它不修改数据库中的任何数据。它只描述一个查询:SELECT。
每个列都有一个类型。以下是标准的 SQL 数据类型
数据类型 | 说明 | 允许的值 | 示例 |
VARCHAR(n) | 最大长度为 n 的字符串 | [0-9a-zA-Z]+{n} |
"foo" |
CHAR(n) | 固定长度为 n 的字符串 | [0-9a-zA-Z]{n} |
"foo" |
SMALLINT | 16 位有符号整数 | \-?[0-9]+ |
584 |
INTEGER | 32 位有符号整数 | \-?[0-9]+ |
-8748 |
FLOAT | 十进制浮点数 | \-?[0-9]+[\.[0-9]+]? |
48.96 |
NUMBER(n,[d]) | n 位数(如果提到,则有 d 位小数位) | \-?[0-9]+[\.[0-9]+]? |
484.65 |
DATE | 日期(YYYY-MM-DD) | [0-9][0-9][0-9][0-9]\-[0-1][0-9]\-[0-3][0-9] |
2009-03-24 |
TIME | 60 分钟的时间段;一天的二十四分之一 | [0-2][0-9]\:[0-5][0-9]\:[0-5][0-9] |
11:24:56 |
TIMESTAMP | 日期和时间 | [0-9]+ |
18648689595962 |
BLOB | 任何二进制数据 | 任何 |
没有布尔类型。整数代替使用。
SELECT 查询的完整语法如下
SELECT[ ALL| DISTINCT] <column name>[[ AS] <alias>][,[ ALL| DISTINCT] <column name>[[ AS] <alias>]]*
FROM <table>[[ AS] <alias>|[[ FULL| LEFT| RIGHT] OUTER| INNER] JOIN <table> ON <expression>]
[, <table>[[ AS] <alias>|[[ FULL| LEFT| RIGHT] OUTER| INNER] JOIN <table> ON <expression>]]*
[WHERE <predicate>[{ AND| OR} <predicate>]*]
[GROUP BY <column name>[, <column name>]*
[HAVING <predicate>[{ AND| OR} <predicate>]]*]
]
[ORDER BY <column name>[ ASC| DESC][, <column name>[ ASC| DESC]]*]
[FETCH FIRST <count> ROWS ONLY];
让我们创建一个包含多个列的表格 reunion
id_reunion | INTEGER |
name | VARCHAR(20) |
description | VARCHAR(255) |
priority | CHAR(1) |
planned | SMALLINT |
date | DATE |
hour | TIME |
duration | INTEGER |
# id_office | INTEGER |
pdf_report | BLOB |
...让我们填充它
id_reunion | name | description | priority | planned | date | hour | duration | # id_office | pdf_report |
---|---|---|---|---|---|---|---|---|---|
1 | Planning | 我们需要计划项目。 | A | 1 | 2008-03-24 | 10:30:00 | 60 | 35 | 48644...846348 |
2 | Progress | 我们做了什么。 | C | 1 | 2008-05-12 | 14:00:00 | 30 | 13 | 9862...15676 |
3 | Change | 我们需要在项目中改变什么。 | B | 1 | 2008-06-03 | 9:30:00 | 90 | 41 | 34876...4846548 |
4 | Presentation | 项目的展示。 | D | 0 | 2008-09-11 | 15:30:00 | 120 | 27 | |
5 | Reporting | 对新手进行解释。 | B | 1 | 2009-03-15 | 14:00:00 | 60 | 7 | 19739...37718 |
6 | Learning | 已安装新软件版本。 | B | 1 | 2009-09-21 | 16:00:00 | 120 | 11 | 785278...37528 |
让我们做一个简单的查询。以下查询只返回 reunion 表的内容
- 查询:
SELECT *
FROM reunion;
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |1 |Planning |We need to plan the project. |A |1 |2008-03-24 |10:30:00 |60 |35 |48644...846348 | |2 |Progress |What we have done. |C |1 |2008-05-12 |14:00:00 |30 |13 |9862...15676 | |3 |Change |What we need to change in the project. |B |1 |2008-06-03 |9:30:00 |90 |41 |34876...4846548 | |4 |Presentation |Presentation of the project. |D |0 |2008-09-11 |15:30:00 |120 |27 |NULL | |5 |Reporting |Explanation to the new beginner. |B |1 |2009-03-15 |14:00:00 |60 |7 |19739...37718 | |6 |Learning |A new software version has been installed. |B |1 |2009-09-21 |16:00:00 |120 |11 |785278...37528 | |----------------------------------------------------------------------------------------------------------------------------------------------------|
结果的形式取决于客户端应用程序。它可以作为文本输出(后端)、HTML 页面(瘦客户端)、程序对象(中间件)等返回... 语句、查询、子句(SELECT、FROM...)、指令和运算符不区分大小写,但它们通常用大写字母书写以提高可读性。
SELECT 和 FROM 子句是 SELECT 查询的两个必需子句
- FROM : 列出查询用于返回数据的表,
- SELECT : 列出要返回的数据。
WHERE 子句不影响查询返回的列,而是影响行。它通过对行应用谓词来过滤行。谓词指定可以为真或假的条件。SQL 可以处理结果未知的条件。例如,以下查询返回优先级级别为 B 的重聚
- 查询:
SELECT *
FROM reunion
WHERE reunion.priority = 'B';
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |3 |Change |What we need to change in the project. |B |1 |2008-06-03 |9:30:00 |90 |41 |34876...4846548 | |5 |Reporting |Explanation to the new beginner. |B |1 |2009-03-15 |14:00:00 |60 |7 |19739...37718 | |6 |Learning |A new software version has been installed. |B |1 |2009-09-21 |16:00:00 |120 |11 |785278...37528 | |----------------------------------------------------------------------------------------------------------------------------------------------------|
如果表名不含糊,则可以省略表名。
与第二个操作数相比,第一个操作数可以是
- 相等 :
=
- 不同 :
<>
- 小于 :
<
- 小于或等于 :
<=
- 大于 :
>
- 大于或等于 :
>=
以下查询返回优先级级别不为 B 的重聚
- 查询:
SELECT *
FROM reunion
WHERE priority <> 'B';
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |1 |Planning |We need to plan the project. |A |1 |2008-03-24 |10:30:00 |60 |35 |48644...846348 | |2 |Progress |What we have done. |C |1 |2008-05-12 |14:00:00 |30 |13 |9862...15676 | |4 |Presentation |Presentation of the project. |D |0 |2008-09-11 |15:30:00 |120 |27 |NULL | |----------------------------------------------------------------------------------------------------------------------------------------------------|
WHERE 子句可以使用 AND(所有条件都必须为真)和 OR(只有一个条件需要为真)运算符包含多个条件。OR 运算符是包含性的(多个条件可以为真)。括号可以指示求值的顺序。NOT 会反转一个条件。以下查询返回优先级级别为 B 并且持续时间超过一小时 或者在 2008/05/12 发生的重聚
- 查询:
SELECT *
FROM reunion
WHERE (priority = 'B' AND NOT duration <= 60) OR date = '2008-05-12';
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |2 |Progress |What we have done. |C |1 |2008-05-12 |14:00:00 |30 |13 |9862...15676 | |3 |Change |What we need to change in the project. |B |1 |2008-06-03 |9:30:00 |90 |41 |34876...4846548 | |6 |Learning |A new software version has been installed. |B |1 |2009-09-21 |16:00:00 |120 |11 |785278...37528 | |----------------------------------------------------------------------------------------------------------------------------------------------------|
LIKE 允许简化的正则表达式匹配。它可以应用于文本列(CHAR、VARCHAR 等)。
- 字母数字字符只匹配相同的文本,
%
是一个通配符,匹配任何文本,_
是一个通配符,匹配任何单个字符,
以下查询返回以 "ing" 结尾且描述中包含 " the " 的重聚
- 查询:
SELECT *
FROM reunion
WHERE name LIKE '%ing' AND description LIKE '% the %';
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |1 |Planning |We need to plan the project. |A |1 |2008-03-24 |10:30:00 |60 |35 |48644...846348 | |5 |Reporting |Explanation to the new beginner. |B |1 |2009-03-15 |14:00:00 |60 |7 |19739...37718 | |----------------------------------------------------------------------------------------------------------------------------------------------------|
BETWEEN 匹配可以是数字、日期或时间的范围值。IN 匹配允许值的列表。以下查询返回在 2008-04-01 和 2009-04-01 之间发生的并且优先级级别为 A、B 或 D 的重聚
- 查询:
SELECT *
FROM reunion
WHERE date BETWEEN '2008-04-01' AND '2009-04-01' AND priority IN ('A', 'B', 'D');
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |3 |Change |What we need to change in the project. |B |1 |2008-06-03 |9:30:00 |90 |41 |34876...4846548 | |4 |Presentation |Presentation of the project. |D |0 |2008-09-11 |15:30:00 |120 |27 |NULL | |5 |Reporting |Explanation to the new beginner. |B |1 |2009-03-15 |14:00:00 |60 |7 |19739...37718 | |----------------------------------------------------------------------------------------------------------------------------------------------------|
EXISTS 通常与子查询一起使用。如果列表(即子查询的结果集)不为空,则该谓词为真。此关键字允许使用与返回行不直接关联的数据(即它们未连接、未链接、未关联... 返回的行),因此在这种情况下无法使用连接来过滤返回的行。例如,我们想要检索所有至少有一个重聚是其他重聚的两倍长的重聚
- 查询:
SELECT *
FROM reunion r1
WHERE EXISTS (
SELECT r2.id_reunion
FROM reunion r2
WHERE r2.duration = r1.duration * 2
);
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |1 |Planning |We need to plan the project. |A |1 |2008-03-24 |10:30:00 |60 |35 |48644...846348 | |2 |Progress |What we have done. |C |1 |2008-05-12 |14:00:00 |30 |13 |9862...15676 | |5 |Reporting |Explanation to the new beginner. |B |1 |2009-03-15 |14:00:00 |60 |7 |19739...37718 | |----------------------------------------------------------------------------------------------------------------------------------------------------|
此查询中使用了另一个重聚的持续时间,而这两个行之间没有连接、链接或关系。如果不使用 EXISTS,则无法完成此条件。请注意,子查询使用别名 r1,而此别名是在主查询中定义的。
EXISTS 也用于匹配缺少的数据。让我们记住 employee 表和 members 表
|
|
以下查询返回未链接到任何项目的员工(即 members 表中没有他们关系的员工)
- 查询:
SELECT *
FROM employees e
WHERE NOT EXISTS (
SELECT m.id_employee
FROM members m
WHERE m.id_employee = e.id_employee
);
- 结果:
|------------------------------------------------------------------| |id_employee |firstname |lastname |phone |mail | |------------|----------|---------|----------|---------------------| |1 |Big |BOSS |936854270 |[email protected] | |------------------------------------------------------------------|
IS NULL 用于测试列是否已填充。它通常用于外键列。
FROM 子句
[edit | edit source]FROM 子句定义用于查询的表,但它也可以联接表。JOIN 创建一个包含两个表列的超级表,用于查询。为了解释联接是什么,我们考虑两个没有主键或外键的古老表
|
|
我们希望将来自不同表列的值关联起来,这些值匹配每个表中给定列的值。
FULL OUTER JOIN
[edit | edit source]联接是通过将一个表上的列与另一个表上的列进行匹配来实现的。在 FULL OUTER JOIN 之后,对于给定值(red),对于一个表上具有此值的给定行([ red | 9999 ]),将为另一个表上匹配的每一行创建一个行([ red | OOOOOO ] 和 [ red | LLLLLL ])。如果一个值仅存在于一个表中,则会创建一个行,并使用 NULL 列将其补全。
FROM table_1 FULL OUTER JOIN table_2 ON table_1.common_value = table_2.common_value
|
|
RIGHT OUTER JOIN
[edit | edit source]RIGHT OUTER JOIN 类似于 FULL OUTER JOIN,但它不会为左表中不存在的值创建行。
FROM table_1 RIGHT OUTER JOIN table_2 ON table_1.common_value = table_2.common_value
|
|
LEFT OUTER JOIN
[edit | edit source]LEFT OUTER JOIN 类似于 FULL OUTER JOIN,但它不会为右表中不存在的值创建行。
FROM table_1 LEFT OUTER JOIN table_2 ON table_1.common_value = table_2.common_value
|
|
INNER JOIN
[edit | edit source]INNER JOIN 类似于 FULL OUTER JOIN,但它仅为左表和右表中都存在的值创建行。
FROM table_1 INNER JOIN table_2 ON table_1.common_value = table_2.common_value
|
|
别名
[edit | edit source]FROM 子句可以声明多个表,用,
隔开,并且可以使用 AS 关键字为表名定义别名,这允许用户使用相同的表进行多次联接。以下查询等同于上面的 INNER JOIN
- 查询:
SELECT *
FROM table_1 AS t1, table_2 AS t2
WHERE t1.common_value = t2.common_value
AS 关键字可以省略。
SELECT 子句
[edit | edit source]SELECT 子句不影响查询处理的数据,而是影响返回给用户的数据。*
返回联接和过滤后的所有处理数据。否则,SELECT 子句将列出用,
隔开的表达式。
表达式可以是表名、表名和用点号隔开的列名,或者如果它不含糊则可以是简单的列名。SELECT 子句还允许使用求值表达式,如加法、减法、串联等。表达式后可以使用 AS 关键字后跟别名。AS 关键字可以省略。
以下是一个例子
- 查询:
SELECT reunion.id_reunion, concat(name, ' : ', reunion.description) n, priority AS p, planned * 10 AS plan, duration + 10 AS reunion_length
FROM reunion;
- 结果:
|-------------------------------------------------------------------------------------------| |id_reunion |n |p |plan |reunion_length | |-----------|------------------------------------------------------|--|-----|---------------| |1 |Planning : We need to plan the project. |A |10 |70 | |2 |Progress : What we have done. |C |10 |40 | |3 |Change : What we need to change in the project. |B |10 |100 | |4 |Presentation : Presentation of the project. |D |0 |130 | |5 |Reporting : Explanation to the new beginner. |B |10 |70 | |6 |Learning : A new software version has been install... |B |10 |130 | |-------------------------------------------------------------------------------------------|
表达式也可以是以下聚合函数
count(*)
:返回行的数量。max(<column_name>)
:列的最大值。min(<column_name>)
:列的最小值。
以下是一个新的例子
- 查询:
SELECT count(*) * 10 AS c, max(date) AS latest_date, min(reunion.date) oldest_date
FROM reunion;
- 结果:
|-----------------------------| |c |latest_date |oldest_date | |---|------------|------------| |60 |2009-09-21 |2008-03-24 | |-----------------------------|
ORDER BY 子句
[edit | edit source]ORDER BY 子句根据一个或多个列对查询返回的行进行排序。排序使用第一个提到的列进行。第二个列用于对第一列中具有相同值的行进行排序,依此类推。可以在每个列之后添加 ASC 或 DESC 关键字。ASC 表示升序排序。DESC 表示降序排序。默认值为降序排序。让我们执行两个简单的请求,第一个只按一个列排序,第二个按两个列排序
- 查询:
SELECT *
FROM reunion
ORDER BY priority ASC;
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |1 |Planning |We need to plan the project. |A |1 |2008-03-24 |10:30:00 |60 |35 |48644...846348 | |3 |Change |What we need to change in the project. |B |1 |2008-06-03 |9:30:00 |90 |41 |34876...4846548 | |5 |Reporting |Explanation to the new beginner. |B |1 |2009-03-15 |14:00:00 |60 |7 |19739...37718 | |6 |Learning |A new software version has been installed. |B |1 |2009-09-21 |16:00:00 |120 |11 |785278...37528 | |2 |Progress |What we have done. |C |1 |2008-05-12 |14:00:00 |30 |13 |9862...15676 | |4 |Presentation |Presentation of the project. |D |0 |2008-09-11 |15:30:00 |120 |27 |NULL | |----------------------------------------------------------------------------------------------------------------------------------------------------|
- 查询:
SELECT *
FROM reunion
ORDER BY priority ASC, duration DESC;
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |1 |Planning |We need to plan the project. |A |1 |2008-03-24 |10:30:00 |60 |35 |48644...846348 | |6 |Learning |A new software version has been installed. |B |1 |2009-09-21 |16:00:00 |120 |11 |785278...37528 | |3 |Change |What we need to change in the project. |B |1 |2008-06-03 |9:30:00 |90 |41 |34876...4846548 | |5 |Reporting |Explanation to the new beginner. |B |1 |2009-03-15 |14:00:00 |60 |7 |19739...37718 | |2 |Progress |What we have done. |C |1 |2008-05-12 |14:00:00 |30 |13 |9862...15676 | |4 |Presentation |Presentation of the project. |D |0 |2008-09-11 |15:30:00 |120 |27 |NULL | |----------------------------------------------------------------------------------------------------------------------------------------------------|
GROUP BY 子句
[edit | edit source]GROUP BY 子句用于聚合操作。它将行收集到组中,例如,所有在给定列中具有相同值的行。在将行收集到组中之后,任何聚合操作都将应用于每个组,而不是一个唯一的大的行组。因此,聚合操作将返回与组数量一样多的结果。组可以使用具有给定列中相同值的,或具有多个给定列中相同值的组合的所有行来形成。例如,我们想知道每个优先级类型的聚会数量
- 查询:
SELECT count(*) as number, priority
FROM reunion
GROUP BY priority;
- 结果:
|-----------------| |number |priority | |-------|---------| |1 |A | |3 |B | |1 |C | |1 |D | |-----------------|
由于 GROUP BY 子句,聚合函数 count(*) 不返回全局计数,而是返回每个优先级级别的计数(A、B、C 和 D)。
- 查询:
SELECT count(*) as number, planned, duration
FROM reunion
GROUP BY planned, duration;
- 结果:
|--------------------------| |number |planned |duration | |-------|--------|---------| |1 |0 |120 | |1 |1 |30 | |2 |1 |60 | |1 |1 |90 | |1 |1 |120 | |--------------------------|
请注意,planned
列有四个值为 1 的组,duration
列有两个值为 120 的组。但是,您可以看到没有两个列中具有相同值的组合的组。
HAVING 子句
[edit | edit source]HAVING 子句与 GROUP BY 子句一起使用。HAVING 子句包含一个谓词,并从返回的行中删除谓词为假的组。例如,我们只想检索至少有两个具有相同优先级级别的聚会的优先级
- 查询:
SELECT priority
FROM reunion
GROUP BY priority
HAVING count(*) > 1;
- 结果:
|---------| |priority | |---------| |B | |---------|
FETCH FIRST 子句
[edit | edit source]FETCH FIRST 子句用于限制返回行的数量。仅返回第一行。返回行的数量是在子句中指示的数量。
- 查询:
SELECT *
FROM reunion
FETCH FIRST 4 ROWS ONLY;
- 结果:
|----------------------------------------------------------------------------------------------------------------------------------------------------| |id_reunion |name |description |priority |planned |date |hour |duration |id_office |pdf_report | |-----------|-------------|-------------------------------------------|---------|--------|-----------|---------|---------|----------|----------------| |1 |Planning |We need to plan the project. |A |1 |2008-03-24 |10:30:00 |60 |35 |48644...846348 | |2 |Progress |What we have done. |C |1 |2008-05-12 |14:00:00 |30 |13 |9862...15676 | |3 |Change |What we need to change in the project. |B |1 |2008-06-03 |9:30:00 |90 |41 |34876...4846548 | |4 |Presentation |Presentation of the project. |D |0 |2008-09-11 |15:30:00 |120 |27 |NULL | |----------------------------------------------------------------------------------------------------------------------------------------------------|
此子句通常用于不返回测试中无用的行或提高性能。
现在您可以探索现有数据库中的所有数据。
SQL 函数
[edit | edit source]- COUNT
- AVG
- MIN
- MAX
- SUM
例如
SELECT '''COUNT(*)''' FROM reunion
返回表 reunion 中的行数。
---
- 另请参见:[[1]]