sql语句select简析

Ⅰ.select通用语法

SELECT 选择列表
FROM 表表达式
[排序声明]
[截取]

Ⅱ.表表达式

1.from子句

FROM table_reference [, table_reference [, ...]]

FROM子句从一个逗号分隔的table_reference列表中,通过jion,生成一个虚拟表。

table_reference可以是一个表名字或者一个生成的表,比如“子查询、表连接、或这些东西的复杂组合”。

如果在FROM子句中列出了多于一个表,那么它们“jion”(连接类型,见下文)形成一个派生表。该派生表可以进行WHERE, GROUP BY, HAVING子句的转换处理,并最后生成表表达式的结果。

交叉连接

T1 CROSS JOIN T2

T1 CROSS JOIN T2对每个来自T1和T2 的行进行组合(也就是,一个笛卡尔积),连接成的表将包含这样的行:所有T1里面的字段后面跟着所有T2 里面的字段。
如果两表分别有 N 和 M 行,连接成的表将有 N*M 行。

FROM T1 CROSS JOIN T2 等效于FROM T1,T2。它还等效于FROM T1 INNER JOIN T2 ON TRUE(见下文)。

条件连接

内连接

T1 [INNER] JOIN T2 ON boolean_expression
T1 [INNER] JOIN T2 USING ( join column list )
T1 NATURAL [INNER] JOIN T2

对于 T1 中的每一行 R1 ,如果能在 T2 中找到一个或多个满足连接条件的行,那么这些满足条件的每一行都在连接表中生成一行。

外连接

T1 { LEFT | RIGHT | FULL } [OUTER] JOIN T2 ON boolean_expression
T1 { LEFT | RIGHT | FULL } [OUTER] JOIN T2 USING ( join column list )
T1 NATURAL { LEFT | RIGHT | FULL } [OUTER] JOIN T2

左外连接(LEFT OUTER JOIN)。首先执行一次内连接。然后为每一个 T1 中无法在 T2 中找到匹配的行生成一行,该行中对应 T2 的列用 NULL 补齐。因此,生成的连接表里总是包含来自 T1 里的每一行至少一个副本。

右外连接(RIGHT OUTER JOIN)。首先执行一次内连接。然后为每一个 T2 中无法在 T1 中找到匹配的行生成一行,该行中对应 T1 的列用 NULL 补齐。因此,生成的连接表里总是包含来自 T2 里的每一行至少一个副本。

全连接(FULL OUTER JOIN)。首先执行一次内连接。然后为每一个 T1 与 T2 中找不到匹配的行生成一行,该行中无法匹配的列用 NULL 补齐。因此,生成的连接表里无条件地包含 T1 和 T2 里的每一行至少一个副本。

ON子句是最常见的连接条件的类型:它接收一个和WHERE 子句相同的布尔表达式。如果两个分别来自T1和T2 的行在ON表达式上运算的结果为真,那么它们就算是匹配的行。

USING是一个连接条件的缩写语法:它接收一个用逗号分隔的字段名列表,这些字段必须是连接表共有的并且其值必须相同。最后,JOIN USING 会将每一对相等的输入字段输出为一个字段,其后跟着所有其它字段。因此,USING (a, b, c) 等效于ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) 只不过是如果使用了ON,那么在结果里a, b和c 字段都会有两个,而用USING的时候就只会有一个(如果使用了SELECT * 的话,他们会优先发生)。

最后,NATURAL是USING的缩写形式:它自动形成一个由两个表中同名的字段组成的USING列表(同名字段只出现一次)。如果没有同名的字段,NATURAL的行为会像CROSS JOIN。

例子:

t1:

num | name
-----+------
   1 | a
   2 | b
   3 | c

t2:

num | value
-----+-------
   1 | xxx
   3 | yyy
   5 | zzz

运行:

=> SELECT * FROM t1 CROSS JOIN t2;
 num | name | num | value
-----+------+-----+-------
   1 | a    |   1 | xxx
   1 | a    |   3 | yyy
   1 | a    |   5 | zzz
   2 | b    |   1 | xxx
   2 | b    |   3 | yyy
   2 | b    |   5 | zzz
   3 | c    |   1 | xxx
   3 | c    |   3 | yyy
   3 | c    |   5 | zzz
(9 rows)

=> SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num;
 num | name | num | value
-----+------+-----+-------
   1 | a    |   1 | xxx
   3 | c    |   3 | yyy
(2 rows)

=> SELECT * FROM t1 INNER JOIN t2 USING (num);
 num | name | value
-----+------+-------
   1 | a    | xxx
   3 | c    | yyy
(2 rows)

=> SELECT * FROM t1 NATURAL INNER JOIN t2;
 num | name | value
-----+------+-------
   1 | a    | xxx
   3 | c    | yyy
(2 rows)

=> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num;
 num | name | num | value
-----+------+-----+-------
   1 | a    |   1 | xxx
   2 | b    |     |
   3 | c    |   3 | yyy
(3 rows)

=> SELECT * FROM t1 LEFT JOIN t2 USING (num);
 num | name | value
-----+------+-------
   1 | a    | xxx
   2 | b    |
   3 | c    | yyy
(3 rows)

=> SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num;
 num | name | num | value
-----+------+-----+-------
   1 | a    |   1 | xxx
   3 | c    |   3 | yyy
     |      |   5 | zzz
(3 rows)

=> SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num;
 num | name | num | value
-----+------+-----+-------
   1 | a    |   1 | xxx
   2 | b    |     |
   3 | c    |   3 | yyy
     |      |   5 | zzz
(4 rows)

=> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num AND t2.value = ‘xxx‘;
 num | name | num | value
-----+------+-----+-------
   1 | a    |   1 | xxx
   2 | b    |     |
   3 | c    |     |
(3 rows)

请注意,将限制放在在WHERE子句中将会产生不同的结果:

=> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num WHERE t2.value = ‘xxx‘;
 num | name | num | value
-----+------+-----+-------
   1 | a    |   1 | xxx
(1 row)

PS:注意最后两个select语句:

用ON声明的连接条件也可以包含与连接不直接相关的条件。这种功能可能对某些查询很有用,但是需要我们仔细想清楚。

这是因为限制放在ON子句中时是先于连接处理的,而限制放在WHERE子句中时是后于连接处理的。

内连接的连接条件既可以写在WHERE子句里也可以写在JOIN子句里。最终效果一样。

对于外连接而言,我们没有选择:连接条件必须在FROM子句中完成。外连接的ON或USING子句不等于WHERE条件,因为它导致最终结果中行的增(那些不匹配的输入行)和删。

2.where子句

WHERE search_condition

这里的search_condition是一个返回类型为 boolean 的值表达式。
在完成对FROM子句的处理之后,生成的每一行都会按照搜索条件进行检查。如果结果是真,那么该行保留在输出表中,否则(也就是结果是假或NULL)就把它抛弃。

PS:这里需要注意的是 where语句中的子查询对from语句中表的字段的引用问题。例如:

SELECT ... FROM fdt WHERE c1 IN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10)

3.group by 子句

SELECT select_list
    FROM ...
    [WHERE ...]
    GROUP BY grouping_column_reference [, grouping_column_reference]...

在通过了WHERE过滤器之后,生成的输入表可以继续用GROUP BY 子句进行分组,然后用HAVING子句选取一些分组行。

GROUP BY 子句子句用于把那些所有列出的 grouping_column_reference值都相同的行聚集在一起,缩减为一行,这样就可以删除输出里的重复或计算聚集。这些字段的列出顺序无关紧要。

group by对select引用字段的限制
凡是在select后面出现的、同时未在聚合函数中出现的字段,必须同时出现在group by后面.被分组的字段可以在选择列表中引用是因为它们每个组都有单一的数值。

例子:

它计算每种产品的总销售额(而不是所有产品的总销售额)。

SELECT product_id, p.name, (sum(s.units) * p.price) AS sales
    FROM products p LEFT JOIN sales s USING (product_id)
    GROUP BY product_id, p.name, p.price;

在这个例子里,字段product_id,p.name 和p.price必须在GROUP BY子句里,因为它们都在查询选择列表里被引用了(但见下文)。s.units字段不必在 GROUP BY列表里,因为它只是在一个聚集表达式(sum(…))里使用,它代表一组产品的销售总额。对于每种产品,这个查询都返回一个该产品的总销售额。

4.having 子句

SELECT select_list FROM ... [WHERE ...] GROUP BY ... HAVING boolean_expression

如果一个表已经用GROUP BY分了组,然后你又只对其中的某些组感兴趣,那么就可以用HAVING子句筛选分组。

groupby对HAVING子句引用字段的限制groupby对Select引用字段的限制

如果一个查询调用了聚合函数,但没有GROUP BY子句,分组仍然发生:结果是单一组行(或者如果单一行被HAVING所淘汰,那么也许没有行)。
同样,它可以只包含一个HAVING子句,没有任何聚合函数的调用或GROUP BY子句。

Ⅲ.排序

SELECT select_list
    FROM table_expression
    ORDER BY sort_expression1 [ASC | DESC]
             [, sort_expression2 [ASC | DESC] ...]

在查询生成输出表之后,也就是在处理完选择列表之后,你还可以对输出表进行排序。如果没有排序,那么行将以不可预测的顺序返回.

sort_expression 是任何可用于选择列表的表达式,例如:

SELECT a, b FROM table1 ORDER BY a + b, c;

如果指定了多个排序表达式,那么仅在前面的表达式排序相等的情况下才使用后面的表达式做进一步排序。每个表达式都可以跟一个可选的ASC(升序,默认) 或DESC(降序)以设置排序方向。升序先输出小的数值,这里的"小"是以<操作符的角度定义的。类似的是,降序是以>操作符来判断的。

注意,排序选项对于每个排序列是相对独立的。例如ORDER BY x, y DESC 意思是说ORDER BY x ASC, y DESC,不同于ORDER BY x DESC, y DESC。

一个sort_expression也可以是字段编号,如:

SELECT a,b, c FROM table1 ORDER BY 1;

Ⅳ.limit截取

SELECT select_list
    FROM table_expression
    [ ORDER BY ... ]
    [ LIMIT { number | ALL } ]

LIMIT子句允许你只取出查询结果中的一部分数据行。LIMIT ALL和省略LIMIT子句是一样的。

使用LIMIT的同时使用ORDER BY子句把结果行约束成一个唯一的顺序是一个好主意。否则你就会得到一个不可预料的子集。

Ⅴ.select 语句大体执行顺序:

1.from子句:通过对表进行各种join,生成一个虚拟表T1。

2.where子句:对虚拟表T1中的每行数据,进行where子句计算,返回True,则表里本行,返回False,则删除本行。过滤后形成虚拟表T2。

3.group by子句:对虚拟表T2进行分组,分组依据是group by 后的表达式。

4.having子句:对分组后的数据,进修再过滤,只能直接引用group by中的字段或者将其他字段作为聚集函数参数使用。形成选择列表T3。

5.order by子句:对T3进行排序。

6.limit子句:截取相应行数。

在这些关键字中,只有在Order By语句中才可以使用最终视图的列名,如:

SELECT FruitName, ProductPlace, Price, ID AS IDE, Discount
FROM T_TEST_FRUITINFO
WHERE (ProductPlace = N‘china‘)
ORDER BY IDE

这里只有在ORDER BY语句中才可以使用IDE,其他条件语句中如果需要引用列名则只能使用ID,而不能使用IDE。

以上内容是根据postgresql文档整理,因为部分语法可能只适用于postgresql,但原理相似。

时间: 2024-11-02 14:40:08

sql语句select简析的相关文章

“取出数据表中第10条到第20条记录”的sql语句+select top 用法

1.首先,select top用法: 参考问题  select top n * from和select * from的区别 select * from table --  取所有数据,返回无序集合 select top n * from table  -- 根据表内数据存储顺序取前n条,返回无序集合 select * from table order by id desc -- 取所有数据,按id逆序返回有序列表 select top n * from table order by id des

“取出数据表中第10条到第20条记录”的sql语句+select top 使用方法

1.首先.select top使用方法: 參考问题  select top n * from和select * from的差别 select * from table --  取全部数据.返回无序集合 select top n * from table  -- 依据表内数据存储顺序取前n条,返回无序集合 select * from table order by id desc -- 取全部数据.按id逆序返回有序列表 select top n * from table order by id d

sql语句select group by order by where一般先后顺序

写的顺序:select ... from... where.... group by... having... order by..执行顺序:from... where...group by... having.... select ... order by... Mysql 全值匹配我最爱,最左前缀要遵守: 带头大哥不能死,中间兄弟不能断: 索引列上少计算,范围之后全失效: LIKE百分写最右,覆盖索引不写星: 不等空值还有or,索引失效要少用. 原文地址:https://www.cnblog

select into outfile的sql语句

         SELECT INTO…OUTFILE语句把表数据导出到一个文本文件中,并用LOAD DATA …INFILE语句恢复数据.但是这种方法只能导出或导入数据的内容,不包括表的结构,如果表的结构文件损坏,则必须先恢复原来的表的结构.     一.SELECT INTO…OUTFILE语法: select * from Table into outfile '/路径/文件名'fields terminated by ','enclosed by '"'lines terminated

用mybatis将SQL查询语句”select * from user”的封装为配置文件

定义一个xml映射文件,文件名见名知意.如user-mapper.xml,文件内容如下: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper

关于T-SQL重编译那点事,WITH RECOMPILE和OPTION(RECOMPILE)区别仅仅是存储过程级重编译和SQL语句级重编译吗

本文出处:http://www.cnblogs.com/wy123/p/6262800.html   在考虑重编译T-SQL(或者存储过程)的时候,有两种方式可以实现强制重编译(前提是忽略导致重编译的其他因素的情况下,比如重建索引,更新统计信息等等), 一是基于WITH RECOMPILE的存储过程级别重编译,另外一种是基于OPTION(RECOMPILE)的语句级重编译. 之前了解的比较浅,仅仅认为是前者就是编译整个存储过程中的所有的语句,后者是重编译存储过程中的某一个语句,也没有追究到底是不

数据库性能优化之SQL语句优化1

一.问题的提出 在 应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用系统提交实 际应用后,随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要的问题之一.系统优化中一个很重要的方面就是SQL语句的优化.对于海 量数据,劣质SQL语句和优质SQL语句之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就可,而是要写出高质量的SQL语句,提 高系统的可用性. 在多数情况下,Oracl

WITH RECOMPILE和OPTION(RECOMPILE)区别仅仅是存储过程级重编译和SQL语句级重编译

在考虑重编译T-SQL(或者存储过程)的时候,有两种方式可以实现强制重编译(前提是忽略导致重编译的其他因素的情况下,比如重建索引,更新统计信息等等), 一是基于WITH RECOMPILE的存储过程级别重编译,另外一种是基于OPTION(RECOMPILE)的语句级重编译. 之前了解的比较浅,仅仅认为是前者就是编译整个存储过程中的所有的语句,后者是重编译存储过程中的某一个语句,也没有追究到底是不是仅仅只有这么一点区别. 事实上在某些特定情况下,两者的区别并非仅仅是存储过程级重编译和语句级重编译的

面试题 | 数据库笔试题集合&#183;之&#183;SQL语句(2)

第2章 SQL 语句 2.1 选择2.1.1 DELETE FROM S WHERE 年龄>60 语句的功能是( A ) A.从 S 表中彻底删除年龄大于 60 岁的记录B.S 表中年龄大于 60 岁的记录被加上删除标记C.删除 S 表D.删除 S 表的年龄列 2.1.2 使用什么命令可以清除表中所有的内容? ( CD ) A.INSERT  B.UPDATE C.DELETE D.TRUNCATE 2.1.3 以下哪个表不用于 mysql 的权限管理( D ) A.HOST