PostgreSQL 教程 -part1 SQL语言

来源:互联网 发布:淘宝买家秀福利店铺名 编辑:程序博客网 时间:2024/05/19 19:15

处理终端界面出现乱码的情况

echo $LANG   //用来查看当前使用的系统语言locale       //查看安装过的语言包LANG="en_US.UTF-8"     //临时更换Linux系统的语言环境Vi  /etc/sysconfig/i18n

解压文件

tar -xzvf file.tar.gz   //解压tar.gztar -xvf file.tar //解压tar 包tar -xzvf file.tar.bz2   //解压tar.bz2tar -xZvf file.tar.Z   //解压tar.Zunrar e file.rar     //解压rar unZip file.zio  //解压Zip

SQL 语言
PostgreSQL是一种关系型数据库管理系统 (RDBMS)。 这意味着它是一种用于管理那些以关系形式存储数据的系统。
每个表都是一个命名的rows的集合。 每一行由一组相同的命名columns组成。 而且每个字段都有一个特定的类型。虽然每个字段在每一行里的位置是固定的, 但一定要记住SQL并未对行在表中的顺序做任何保证(但你可以对它们进行明确的排序显示)。
表组成数据库,一个由某个PostgreSQL服务器管理的数据库集合组成一个数据库cluster。
创建新表
可以通过声明表的名字和所有字段的名字及其类型来创建表:

CREATE TABLE weather (    city            varchar(80),    temp_lo         int,           -- low temperature    temp_hi         int,           -- high temperature    prcp            real,          -- precipitation    date            date);

psql可以识别该命令直到分号才结束。

可以在SQL命令中自由使用空白(空格/tab/换行符)。 这意味着你可以用和上面不同的对齐方式(甚至在同一行中)键入命令。 双划线("--")引入注释,任何跟在它后面的东西直到该行的结尾都被忽略。 SQL是对关键字和标识符大小写不敏感的语言, 只有在标识符用双引号包围时才能保留它们的大小写属性(上面没有这么干)。 varchar(80)声明一个可以存储最长80个字符的任意字符串的数据类型。 int是普通的整数类型。 real是一种用于存储单精度浮点数的类型。 date类型应该可以自解释。 没错,类型为date的字段名字也是date。 这么做可能比较方便,也可能容易让人混淆;PostgreSQL支持标准的SQL类型: int,smallint,real,double precision,char(N), varchar(N),date, time,timestamp,和interval 还支持其它的通用类型和丰富的几何类型。 PostgreSQL允许你自定义任意数量的数据类型。 因而类型名并不是语法关键字, 除了SQL标准要求支持的特例外 第二个例子将保存城市和它们相关的地理位置:
CREATE TABLE cities (    name            varchar(80),    location        point);

point类型就是一种PostgreSQL特有的数据类型
最后,我们还要提到如果你不再需要某个表, 或者你想创建一个不同的表,那么你可以用下面的命令删除它:

DROP TABLE tablename;

向表中添加行
INSERT语句用于向表中添加行:

INSERT INTO weather VALUES ('San Francisco', 46, 50, 0.25, '1994-11-27');

注意所有数据类型都使用了相当明了的输入格式。 那些不是简单数字值的常量必需用单引号(‘)包围, 就像在例子里一样。 date类型实际上对可接收的格式相当灵活

point类型要求一个座标对作为输入,如下:

INSERT INTO cities VALUES ('San Francisco', '(-194.0, 53.0)');

到目前为止使用的语法要求你记住字段的顺序。 一个可选的语法允许你明确地列出字段:

INSERT INTO weather (city, temp_lo, temp_hi, prcp, date)    VALUES ('San Francisco', 43, 57, 0.0, '1994-11-29');

如果需要,你可以用另外一个顺序列出字段或者是忽略某些字段, 比如说,我们不知道降水量:

INSERT INTO weather (date, city, temp_hi, temp_lo)    VALUES ('1994-11-29', 'Hayward', 54, 37);

还可以使用COPY从文本文件中装载大量数据。 这么干通常更快,因为COPY命令就是为这类应用优化的, 只是比INSERT少一些灵活性。比如:

COPY weather FROM '/home/user/weather.txt';

这里源文件的文件名必须是后端服务器可访问的,而不是客户端可访问的,因为后端服务器直接读取文件。

查询一个表
要从一个表中检索数据就是queried这个表。 SQL的SELECT语句就是做这个用途的。 该语句分为选择列表(列出要返回的字段)、表列表(列出从中检索数据的表)、以及可选的条件(声明任意限制)。 比如,要检索表weather的所有行,键入

SELECT * FROM weather;

这里的*是”all columns”的缩写。 [1] 因此同样的结果可以用下面的语句获得

SELECT city, temp_lo, temp_hi, prcp, date FROM weather;

而输出应该是:

 city      | temp_lo | temp_hi | prcp |    date---------------+---------+---------+------+------------ San Francisco |      46 |      50 | 0.25 | 1994-11-27 San Francisco |      43 |      57 |    0 | 1994-11-29 Hayward       |      37 |      54 |      | 1994-11-29(3 rows)

你可以在选择列表中写任意表达式,而不仅仅是字段列表。比如,你可以:

SELECT city, (temp_hi+temp_lo)/2 AS temp_avg, date FROM weather;

这样应该得到:

     city      | temp_avg |    date---------------+----------+------------ San Francisco |       48 | 1994-11-27 San Francisco |       50 | 1994-11-29 Hayward       |       45 | 1994-11-29(3 rows)

请注意这里的AS子句是如何给输出字段重新命名的。 AS子句是可选的。

 一个查询可以使用WHERE子句进行"qualified", 声明需要哪些行。WHERE子句包含一个布尔表达式, 只有那些布尔表达式为真的行才会被返回。 允许你在条件中使用常用的布尔操作符(AND, OR,和NOT)。 比如,下面的查询检索旧金山的下雨天的天气:
SELECT * FROM weather    WHERE city = 'San Francisco' AND prcp > 0.0;

结果如下:

 city      | temp_lo | temp_hi | prcp |    date---------------+---------+---------+------+------------ San Francisco |      46 |      50 | 0.25 | 1994-11-27(1 row)

你可以要求返回的查询是排好序的:

SELECT * FROM weather    ORDER BY city;     city      | temp_lo | temp_hi | prcp |    date---------------+---------+---------+------+------------ Hayward       |      37 |      54 |      | 1994-11-29 San Francisco |      43 |      57 |    0 | 1994-11-29 San Francisco |      46 |      50 | 0.25 | 1994-11-27

在这个例子里,排序的顺序并非绝对清晰的,因此你可能看到San Francisco行随机的排序。 但是如果你使用下面的语句,那么就总是会得到上面的结果:

SELECT * FROM weather    ORDER BY city, temp_lo;

你可以要求查询的结果按照某种顺序排序,并且消除重复行的输出:

SELECT DISTINCT city    FROM weather;     city--------------- Hayward San Francisco(2 rows)

再次声明,结果行的顺序可能是随机的。 你可以组合使用DISTINCT和ORDER BY来获取一致的结果: [2]

SELECT DISTINCT city    FROM weather    ORDER BY city;

表间链接
查询可以一次访问多个表,或者用某种方式访问一个表, 而同时处理该表的多个行。 一个同时访问同一个或者不同表的多个行的查询叫连接查询。
举例来说,比如你想列出所有天气记录以及这些记录相关的城市。 要实现这个目标, 我们需要拿weather表每行的city字段和 cities表所有行的name字段进行比较, 并选取那些这些数值相匹配的行。
这个任务可以用下面的查询来实现:

SELECT *    FROM weather, cities    WHERE city = name;     city      | temp_lo | temp_hi | prcp |    date    |     name      | location---------------+---------+---------+------+------------+---------------+----------- San Francisco |      46 |      50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco |      43 |      57 |    0 | 1994-11-29 | San Francisco | (-194,53)(2 rows)

观察结果集的两个方面:
没有城市Hayward的结果行。 这是因为在cities表里面没有与Hayward匹配的行, 所以连接忽略了weather表里的不匹配行。 我们稍后将看到如何修补这个问题。
有两个字段包含城市名。这是正确的, 因为weather和cities表的字段是接在一起的。 不过,实际上我们不想要这些, 因此你将可能希望明确列出输出字段而不是使用*:

SELECT city, temp_lo, temp_hi, prcp, date, location    FROM weather, cities    WHERE city = name;

因为这些字段的名字都不一样, 所以分析器自动找出它们属于哪个表, 但是如果两个表中有重复的字段名, 你就必须使用字段全称qualify你想要的字段:

SELECT weather.city, weather.temp_lo, weather.temp_hi,       weather.prcp, weather.date, cities.location    FROM weather, cities    WHERE cities.name = weather.city;

一般认为在连接查询里使用字段全称是很好的风格, 这样,即使在将来向其中一个表里添加了同名字段也不会引起混淆。

到目前为止,这种类型的连接查询也可以用下面这样的形式写出来:

SELECT *    FROM weather INNER JOIN cities ON (weather.city = cities.name);

现在我们将看看如何能把Hayward记录找回来。 我们想让查询干的事是扫描weather表, 并且对每一行都找出匹配的cities表里面的行。 如果没有找到匹配的行,那么需要一些”empty values”代替cities表的字段。 这种类型的查询叫 外连接(我们在此之前看到的连接都是内连接)。 这样的命令看起来像这样:

SELECT *    FROM weather LEFT OUTER JOIN cities ON (weather.city = cities.name);     city      | temp_lo | temp_hi | prcp |    date    |     name      | location---------------+---------+---------+------+------------+---------------+----------- Hayward       |      37 |      54 |      | 1994-11-29 |               | San Francisco |      46 |      50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco |      43 |      57 |    0 | 1994-11-29 | San Francisco | (-194,53)(3 rows)

这个查询是一个left outer join, 因为连接操作符左边的表中的行在输出中至少出现一次, 而右边的表中的行只输出那些与左边的表有匹配的行。 如果输出的左表中的行没有右表中的行与其对应, 那么右表中的字段将填充为NULL 。
我们也可以把一个表和自己连接起来。 这叫self join。比如,假设我们想找出那些在其它天气记录的温度范围之外的天气记录。 这样我们就需要拿weather 表里每行的temp_lo和temp_hi字段与 weather表里其它行的temp_lo和temp_hi字段进行比较。 我们可以用下面的查询实现这个目标:

SELECT W1.city, W1.temp_lo AS low, W1.temp_hi AS high,    W2.city, W2.temp_lo AS low, W2.temp_hi AS high    FROM weather W1, weather W2    WHERE W1.temp_lo < W2.temp_lo    AND W1.temp_hi > W2.temp_hi;     city      | low | high |     city      | low | high---------------+-----+------+---------------+-----+------ San Francisco |  43 |   57 | San Francisco |  46 |   50 Hayward       |  37 |   54 | San Francisco |  46 |   50(2 rows)

在这里我们把 weather 表重新标记为W1和W2以区分连接的左边和右边。 你还可以用这样的别名在其它查询里节约一些敲键,比如:

SELECT *    FROM weather w, cities c    WHERE w.city = c.name;

聚集函数
PostgreSQL支持聚集函数。 一个聚集函数从多个输入行中计算出一个结果。 比如,我们有在一个行集合上计算count,sum, avg,max和 min的函数。

比如,我们可以用下面的语句找出所有低温中的最高温度:

SELECT max(temp_lo) FROM weather; max-----  46(1 row)

如果我们想知道该读数发生在哪个城市,可能会用:

SELECT city FROM weather WHERE temp_lo = max(temp_lo);     WRONG

不过这个方法不能运转, 因为聚集函数max不能用于WHERE子句中。 存在这个限制是因为WHERE子句决定哪些行可以进入聚集阶段; 因此它必需在聚集函数之前计算。 不过,我们可以用其它方法实现这个目的; 这里我们使用subquery:

SELECT city FROM weather    WHERE temp_lo = (SELECT max(temp_lo) FROM weather);     city--------------- San Francisco(1 row)

这样做是可以的,因为子查询是一次独立的计算,它独立于外层查询计算自己的聚集。

聚集同样也常用于GROUP BY子句。比如,我们可以获取每个城市低温的最高值:

SELECT city, max(temp_lo)    FROM weather    GROUP BY city;     city      | max---------------+----- Hayward       |  37 San Francisco |  46(2 rows)

这样每个城市一个输出。每个聚集结果都是在匹配该城市的行上面计算的。 我们可以用HAVING过滤这些分组:

SELECT city, max(temp_lo)    FROM weather    GROUP BY city    HAVING max(temp_lo) < 40;  city   | max---------+----- Hayward |  37(1 row)

这样就只给出那些temp_lo值曾经有低于40度的城市。 最后,如果我们只关心那些名字以”S”开头的城市,我们可以用:

SELECT city, max(temp_lo)    FROM weather    WHERE city LIKE 'S%'(1)    GROUP BY city    HAVING max(temp_lo) < 40;

理解聚集和SQL的WHERE和HAVING子句之间的关系非常重要。 WHERE和HAVING的基本区别如下: WHERE在分组和聚集计算之前选取输入行(它控制哪些行进入聚集计算), 而HAVING在分组和聚集之后选取输出行。 因此,WHERE子句不能包含聚集函数; 因为试图用聚集函数判断那些行将要输入给聚集运算是没有意义的。 相反,HAVING子句总是包含聚集函数。 当然,你可以写不使用聚集的HAVING子句,但这样做没什么好处, 因为同样的条件可以更有效地用于WHERE阶段。

在前面的例子里,我们可以在WHERE里应用城市名称限制, 因为它不需要聚集。这样比在HAVING里增加限制更加高效, 因为我们避免了为那些未通过WHERE检查的行进行分组和聚集计算。
更新
你可以用UPDATE命令更新现有的行。 假设你发现所有11月28日的温度计数都低了两度,那么你就可以用下面的方式更新数据:

UPDATE weather    SET temp_hi = temp_hi - 2,  temp_lo = temp_lo - 2    WHERE date > '1994-11-28';

看看数据的新状态:

SELECT * FROM weather;     city      | temp_lo | temp_hi | prcp |    date---------------+---------+---------+------+------------ San Francisco |      46 |      50 | 0.25 | 1994-11-27 San Francisco |      41 |      55 |    0 | 1994-11-29 Hayward       |      35 |      52 |      | 1994-11-29(3 rows)

删除

数据行可以用DELETE命令从表中删除。 假设你对Hayward的天气不再感兴趣,那么你可以用下面的命令把那些行从表中删除:

DELETE FROM weather WHERE city = 'Hayward';

所有属于 Hayward 的天气记录都将被删除。

SELECT * FROM weather;     city      | temp_lo | temp_hi | prcp |    date---------------+---------+---------+------+------------ San Francisco |      46 |      50 | 0.25 | 1994-11-27 San Francisco |      41 |      55 |    0 | 1994-11-29(2 rows)

使用下面形式的语句时一定要小心:

DELETE FROM tablename;

如果没有指定条件,DELETE将从指定表中删除所有行。做这些之前系统不会请求你确认!

0 0
原创粉丝点击