随便玩玩之PostgreSQL(第二章)单表数据查询

随便玩玩之PostgreSQL(第二章)单表数据查询

未经授权不得转载


第二章 单表数据查询
数据库的基本功能就是数据增查改删,倘若不可以,要她还有什么意义。数据查询功能不仅仅是查询,而且还能筛选,并且格式化显示。
数据查询使用SELECT语句,本章介绍如何使用SELECT查询(列出)数据库中的数据。


2.1查询数据库cj表中全部信息
方法一:使用“*”通配符查询所有数据(所有字段数据)。

SELECT * FROM cj;

结果如图。



方法二:制定所有字段(列名)。每个字段用逗号(,)隔开。

SELECT id,kc,bj,xm,yw,sx,yy FROM cj;

结果如图。


2.2查询数据库中指定字段信息(只显示出想要的列)。
只要是表内的字段就可以,重复也可以,字段数量最多1664个。

SELECT xm,yw FROM cj;

结果列出所有学生的姓名和语文成绩。




2.4查询指定记录(只显示想要的行)。
数据库的信息本来就包含了各种信息,如cj表中包括一班、二班、三班的每一个学生的考试成绩。倘若查询一班所有人的成绩,可以查出所有人的成绩,然后在EXCEL中删掉二班、三班的。数据量少的时候可以这样,数据量多的时候速度就会下降。不过,我们可以通过限制查询条件进行查询,按条件查询(列出)数据。

SELECT * FROM cj WHERE bj='一班';

结果如图。

 语句中的等号(=)表示只查询bj字段为一班的学生的成绩。等号为判断符,其他判断符为<>(或者!=,表示不等于),<(表示左边数值小于右边数值),<=(表示小于等于右边数值),>(表示大于右边数值),>=(表示大于等于右边数值),BETWEEN AND(表示介于两个数值之间)。
如:

 1 --查询语文成绩大于60的学生。
 2 SELECT * FROM cj WHERE yw > 60;
3 --查询语文成绩在60到69之间的学生。 4 SELECT id,bj,xm,yw FROM cj WHERE yw BETWEEN 60 AND 69; 5 --或者 6 SELECT id,bj,xm,yw FROM cj WHERE yw>=60 AND yw<69; --结果与第四行语句相同。
7 --查询语文成绩不是60到69的学生。 8 SELECT * FROM cj WHERE yw NOT BETWEEN 60 AND 69; 9 --或者 10 SELECT * FROM cj WHERE yw>69 OR yw <60;
11 --查询英语成绩等60的学生。 12 SELECT * FROM cj WHERE yy=60
13 --查询英语成绩等于60且必须等于70的学生(无意义,没结果且不合逻辑)。 14 SELECT * FROM cj WHERE yy=60 AND yy=70;
15 --查询张三的成绩。 16 SELECT * FROM cj WHERE xm=’张三’;
17 --查询张三其中考试的成绩。 18 SELECT * FROM cj WHERE xm='张三' AND kc='期中考试';
19 --查询语文成绩大于80和(或)小于65的学生。 20 SELECT * FROM cj WHERE yw > 80 OR yw<65;

 

2.4多条件查询
多条件查询使用AND或OR操作符,可以指定2个及以上的条件。

AND操作符限定满足所有条件才会有记录返回。
如:查询期中考试三班语文成绩大于80的学生。

SELECT * FROM cj WHERE kc='期中考试' AND bj='三班' AND yw>80;

OR操作符只需所有条件中满足一个条件即可。
如:查询语文成绩大于80或一班的学生。

SELECT * FROM cj WHERE yw>80 OR bj='一班';

用IN操作符实现OR操作符功能。
如:查询英语成绩等于60和(或)70的学生。

--OR操作符
SELECT * FROM cj WHERE yy=60 OR yy=70;
--IN操作符
SELECT * FROM cj WHERE yy in (60,70);

 2.5 去掉查询结果中的重复记录。
cj表中共有18个学生的信息,每一个信息都有一个班级。想要从表中得到有多少个班级,只有查询出所有班级字段,然后去掉重复的,只保留一个,即可得到班级数量。使用DISTINCT关键字即可去掉重复记录,只保留一个记录值。

SELECT DISTINCT bj FROM cj;

结果如图。

结果把所有的班级只列出一个,只需要数一数有多少行即可得出有三个班级。

也有不想数行的方法,使用count()函数即可实现。

SELECT  count(DISTINCT bj)  FROM cj;

结果如图。


2.6对查询结果排序
默认查询结果没有排序,有可能每次的查询结果顺序都不一样。使用ORDER BY子句可以对结果进行排序。
如:从低到高列出所有学生的语文成绩。

SELECT xm,yw,bj,kc FROM cj ORDER BY yw;

结果如图。


如:先分期中考试、期末考试,在从低到高列出所有学生语文成绩。

SELECT kc,yw,bj,xm FROM cj ORDER BY kc,yw;

结果如图。


默认排序为1-9,A-Z,逆序排列只需要在字段后加DESC关键字即可,DESC约束其前的字段,如果对所有排序条件逆序,需在所有关键字后加DESC。
如:列出从高到低列出所有学生期中考试语文成绩。

SELECT kc,yw,bj,xm FROM cj WHERE kc='期中考试' ORDER BY kc,yw DESC;

结果如图。


2.7查询结果分组
分组排序使用GROUP BY子句。
但是分组之后组字段显示的值是什么?做班级成绩汇报时,一般说一班有多少个人,语文平均分是多少,语文最高分是多少,最低分是多少,不会说出每个人的成绩,也不会随便说一个人的成绩。所以分组之后显示的是计算的结果,计算使用聚合函数。常用的聚合函数有:计数量count(),求最大值max(),求最小值min(),计总和sum(),求平均avg()。
如:计算出各班的期中考试平均。

SELECT bj,avg(yw),avg(sx),avg(yy) FROM cj WHERE kc='期中考试' GROUP BY bj;

结果如图。


小数点太多?可以用round()函数截取。

SELECT bj,round(avg(yw),2),avg(sx),avg(yy) FROM cj WHERE kc='期中考试' GROUP BY bj;

结果如图。

一行的SQL语句太长?可以分行写SQL语句,只要在最后有一个分号就可以。

SELECT     bj,
         round(avg(yw),2),
         avg(sx),avg(yy)
    FROM cj
    WHERE kc='期中考试'
    GROUP BY bj;

结果如图。

语句换行不影响查询结果。


表头都是AVG,不美观?使用AS关键字设置别名即可。

SELECT     bj AS "班级",
         round(avg(yw),2) AS "语文平均分",
         avg(sx)  AS "数学平均分",
         avg(yy)  AS "英语平均分"
    FROM cj
    WHERE kc='期中考试'
    GROUP BY bj;

结果如图。

AS的功能是给字段起一个别名。


数据没有排序,看起来不方便?分组之后再排序。

SELECT     bj AS "班级",
         round(avg(yw),2) AS "语文平均分",
         avg(sx)  AS "数学平均分",
         avg(yy)  AS "英语平均分"
    FROM cj
    WHERE kc='期中考试'
    GROUP BY bj
    ORDER BY avg(yw);

结果如图。

注:最后的ORDER BY指定的不是字段本身,而是使用聚合函数计算后的字段。已经给avg(yw)设置了别名,那么ORDER BY 能使用别名作为排序条件吗?当然可以。

SELECT     bj AS "班级",
         round(avg(yw),2) AS "语文平均分",
         avg(sx)  AS "数学平均分",
         avg(yy)  AS "英语平均分"
    FROM cj
    WHERE kc='期中考试'
    GROUP BY bj
    ORDER BY "语文平均分";

结果如图。


 

2.8查询结果分组排序后再筛选
使用WHERE关键字可以筛选过滤数据,但是WHERE的筛选只能是指定选择记录的条件,请记住:WHERE关键字是用在记录上的。对于分组之后的组有该如何筛选?HAVING关键字用来筛选分组之后的数据。
如:筛选出期中考试语文平均分大于70的班级。

SELECT   bj AS "班级",
             round(avg(yw),2) AS "语文平均分",
             avg(sx)  AS "数学平均分",
             avg(yy)  AS "英语平均分"
    FROM cj
    WHERE kc='期中考试'
    GROUP BY bj
    HAVING avg(yw)>70;        

结果如图。


2.9限制查询结果数量。
SELECT将返回所有匹配的行,可能是表中的所有行,如仅仅需要返回第一行或前几行,使用LIMIT关键字。
如:查询cj前3行的数据。

SELECT * FROM cj LIMIT 3;

结果如图。


也可以查询从第4行开始的3条记录。

SELECT * FROM cj LIMIT 3 OFFSET 4;

结果如图。


数据库本身的记录(行)从0开始计算,第4行应理解为数据库的第5个记录。


2.10 阶段性总结示例:使用聚合函数实现分类汇总
count()函数计算表内行的总数。方法有两种:count(*)计算表内行的总数,包括空值。Count(字段名)计算指定列行的总数,忽略空值。
sum()函数计算一个列的所有记录累计总和。
avg()函数计算一个列的所有记录的平均值。
Max()函数返回一个列的所有记录中的最大值。
Min()函数返回一个列的所有记录中的最小值。
如:分类汇总功能。

 1 SELECT   bj                          AS "班级"         ,
 2          count(xm)                   AS "人数"         ,
 3          round(sum(yw)/count(xm),2)  AS "语文"         ,
 4       -- round(avg(yw),2)            AS "语文"         ,
 5          max(yw)                     AS "语文最高分"    ,
 6          min(yw)                     AS "语文最低分"    ,
 7          round(avg(sx),2)            AS "数学平均分"    ,
 8          max(sx)                     AS "数学最高分"    ,
 9          min(sx)                     AS "数学最低分"    ,
10          round(avg(yy),2)            AS "英语平均分"    ,
11          max(yy)                     AS "英语最高分"    ,
12          min(yy)                     AS "英语最低分"
13     FROM cj
14     WHERE kc = '期中考试'
15     GROUP BY bj
16     ORDER BY avg(yw);

结果如图。

使用方法非常灵活,一条语句搞定。


 

 2.11子查询
子查询是把一个查询嵌套在另一个查询中。子查询又叫内部查询,相对于内部查询,包含着子查询的叫外部查询。
子查询可以包含普通select可以包括的任何子句,比如:distinct、 group by、order by、limit、join和union等;但是对应的外部查询必须是以下语句之一:select、insert、update、delete、set或 者do。
子查询可以在SELECT后,FROM后,WHERE后,GROUP BY后和ORDER BY后。
根据返回值类型,子查询分为标量子查询(单一值子查询,返回一个值)、列子查询(返回一列值)、行子查询(返回一行值)、表子查询(返回一个表的值),
可以使用的操作符:= > < >= <= <> ANY IN SOME ALL EXISTS 。
2.11.1标量子查询
标量子查询返回一个值,可以与外部查询使用=、>、<、>=、<=和<>符号进行比较判断,如果子查询返回的不是一个标量值,而外部查询使用了比较符和子查询的结果进行了比较,那么就会抛出异常。
如:查询期中考试语文成绩高于张三的学生。

1 SELECT * 
2     FROM cj 
3     WHERE yw > 
4         (SELECT yw FROM cj WHERE kc='期中考试' AND xm ='张三') 
5         AND kc='期中考试';

结果如图:

得到的结果是把期中考试语文成绩高于张三的学生全部列出来,最后的AND kc='期中考试'判断条件是将结果限定在期中考试内,去掉这一句会列出期中考试和期末考试成绩。

其执行循序为:先执行(SELECT yw FROM cj WHERE kc='期中考试' AND xm = '张三'),得到张三的期中考试语文成绩,为64,再和yw>组成判断表达式yw>64;yw>64和AND kc='期中考试'组成逻辑与表达式(两个结果都为真),最后执行外部语句(整个语句)

关于子查询请记住,语句里有括号,则先执行括号内部查询(子查询),得到结果,作为外部查询的一部分,再执行部查询

也可以把子查询放在SELECT后。

如:查询张三的期中考试和期末考试语文成绩,以及两者之间的差距。

SELECT  xm    AS "姓名" ,
        yw    AS "期中考试" ,
        (SELECT yw FROM cj WHERE kc='期末考试' AND xm='张三')       AS "期末考试" ,
        yw - (SELECT yw FROM cj WHERE kc='期末考试' AND xm='张三')  AS "差距"
    FROM   cj
    WHERE  kc='期中考试' AND xm='张三';

结果如下:

如上所释,先执行括号内语句(子查询),结果作为外部语句(整个语句)组成部分,再执行外部语句

2.11.2列子查询

列子查询返回一个列的数据,可以使用 = > < >= <= <> 这些操作符对子查询的结果进行比较,通常子查询的位置在比较式的右侧。可以使用 IN、ANY、SOME 和 ALL 操作符,不能直接使用 = > < >= <= <> 这些比较标量结果的操作符。

ALL操作符是所有、全部的意思。只有全部符合条件,外部语句才有结果。例如,>(1,2,3)表示必须大于3。(注:NOT IN 与<>ALL等效)

如:查询语文成绩比数学最高分还高的同学。

SELECT
       xm     AS "姓名" ,
       yw     AS "语文成绩" ,
       (SELECT max(sx) FROM cj)   AS "全部学生数学最高分"
    FROM cj
    WHERE yw > ALL (SELECT sx FROM cj);   --左边大于右边最大的

结果如图。

ANY操作符是任意一个的意思。满足任何一个即可。例如:>ANY(1,2,3)表示大于1即可。

SOME操作符与ANY相同。

如:查询数学成绩比语文最低分高的学生。

SELECT  xm  AS "姓名",
        sx  AS "数学",
        (SELECT min(yw) FROM cj)  AS "语文最低分"
    FROM cj
    WHERE sx > ANY (SELECT yw FROM cj)
    ORDER BY sx DESC;

结果如图。

当判断对象中一个是另一个的子集时,ANY与IN等效,结果一样。

 2.11.3行子查询

如:查询表内信息是否在另一个表中完全一致。

SELECT * 
    FROM (SELECT * FROM cj WHERE id = 5) id5  --FROM后的子查询得到一行数据
    WHERE (id,kc,bj,xm,yw,sx,yy) IN (SELECT * FROM cj);

结果如图。

2.11.4表子查询

结果得到一个表。

如:查询所有学生的期中考试成绩。

1 SELECT * 
2     FROM (SELECT * FROM cj WHERE kc='期中考试') kc_qz;
3 -- 和 SELECT * FROM cj WHERE kc='期中考试'; 语句的执行结果相同,不同的是查询的表不一样。

结果如下。

代码内有注释。结果相同,查询的表不相同。行3的语句是直接从cj表内查询;行2的语句是执行一个查询,得到的结果为表。

注:给表起别名只需在表后加空格和名称。

 2.11.5 阶段性总结示例:利用子查询求班级平均分差距。

 1 SELECT kc_qz.bj    AS "期中班级"                          ,
 2        kc_qm.bj    AS "期末班级"                          , 
 3     -- 增加班级一列(kc_qm.bj),用来识别班级,无特殊意义
 4        round(kc_qz.yw1,2)                AS "期中语文"    ,
 5        round(kc_qm.yw2,2)                AS "期末语文"    , 
 6        round(kc_qm.yw2-kc_qz.yw1,2)      AS "语文差距"    , 
 7     -- 分数差距,正数表示期末考试相对期中考试有提升,负数表示下降
 8        round(kc_qz.sx1,2)                AS "期中数学"    ,
 9        round(kc_qm.sx2,2)                AS "期末数学"    ,
10        round(kc_qm.sx2 - kc_qz.sx1,2)    AS "数学差距"    ,
11        round(kc_qz.yy1,2)                AS "期中英语"    ,
12        round(kc_qm.yy2,2)                AS "期末英语"    ,
13        round(kc_qm.yy2 - kc_qz.yy1,2)    AS "英语差距"
14     FROM
15         (SELECT bj,
16                 avg(yw) AS "yw1",
17                 avg(sx) AS "sx1",
18                 avg(yy) AS "yy1"
19             FROM cj
20             WHERE kc='期中考试'
21             GROUP BY bj) kc_qz,
22         (SELECT bj,
23                avg(yw) AS "yw2",
24                avg(sx) AS "sx2",
25                avg(yy) AS "yy2"
26             FROM cj
27             WHERE kc='期末考试'
28             GROUP BY bj) kc_qm
29     WHERE  kc_qz.bj = kc_qm.bj      -- 表连接查询,下一章内容
30     ORDER BY kc_qz.bj;

结果如图。

看起来是30行,实际上只是一条语句。

 

至此,第二章结束,简单介绍了单表查询,语句都很简单,但是很神奇。

 

posted @ 2017-11-10 21:02  冲浪的奶糖  阅读(6947)  评论(0编辑  收藏  举报