| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 20527 人关注过本帖
标题:[翻译]MySQL5.0用户手册——第三章:快速入门
取消只看楼主 加入收藏
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

3.3.4.8. 行统计

数据库经常被用来回答这样的问题, “ 一个特定类型的数据在表中出现的频率如何?” 例如,你可能想知道你总共有多少只宠物, 或每一个主人拥有多少只宠物, 或者你想对你的宠物进行各种各样的统计。

你总共拥有多少只宠物等同于 “pet数据表里有多少行记录”, 因为每一只宠物的信息作为一行记录,COUNT(*) 统计行的总数,所以查找总共有多少宠物的语句如下:

mysql> SELECT COUNT(*) FROM pet;
+----------+
| COUNT(*) |
+----------+
|        9 |
+----------+

以前,我们找出过宠物的主人有哪些,现在,你可以使用COUNT() 来找出每一个主人分别拥有几只宠物:

mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
+--------+----------+
| owner  | COUNT(*) |
+--------+----------+
| Benny  |        2 |
| Diane  |        2 |
| Gwen   |        3 |
| Harold |        2 |
+--------+----------+

请注意GROUP BY 是用来把记录按照宠物的主人分组, 否则,你将得到一条错误信息:

mysql> SELECT owner, COUNT(*) FROM pet;
ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) 
with no GROUP columns is illegal if there is no GROUP BY clause

COUNT()GROUP BY 可以让你以各种各样的方式展示数据表中的数据,下面的例子显示了对pet表的各种统计操作:

按类别统计动物的数量:

mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| bird    |        2 |
| cat     |        2 |
| dog     |        3 |
| hamster |        1 |
| snake   |        1 |
+---------+----------+

按性别统计动物的数量:

mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+------+----------+
| sex  | COUNT(*) |
+------+----------+
| NULL |        1 |
| f    |        4 |
| m    |        4 |
+------+----------+

(在这里,NULL表示不清楚动物的性别。)

按类别和性别统计动物的数量:

mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | NULL |        1 |
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

使用COUNT()时,你也不是一定要提取整个表的数据,例如,在前面的查询中,如果你只对猫和狗感兴趣,可以使用如下语句:

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE species = 'dog' OR species = 'cat'
    -> GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
+---------+------+----------+

如果你只想知道已知性别的动物的统计资料,如下:

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE sex IS NOT NULL
    -> GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

3.3.4.9. 使用多个表

pet表只是保存了你所拥有的宠物的基本信息,或许你还需要保存其它的信息,诸如象它们生活中发生的一些事件,比如什么时候看兽医了,什么时候生小动物了等等。这个表应该是个什么样子呢?它需要:

  • 需要包含宠物的名字,以便你能知道是发生在哪知宠物身上的事件。

  • 一个时间,以便你能知道事件是什么时候发生的。

  • 一个描述事件的字段。

  • 一个事件类型字段,以便你能将事件进行分类。

出于这些考虑,event表的CREATE TABLE 语句应该看起来象这样:

mysql> CREATE TABLE event (name VARCHAR(20), date DATE,
    -> type VARCHAR(15), remark VARCHAR(255));

pet 表一样,可以创建一个以tab符分割的文本文件来载入初始化数据:

name date type remark
Fluffy 1995-05-15 litter 4 kittens, 3 female, 1 male
Buffy 1993-06-23 litter 5 puppies, 2 female, 3 male
Buffy 1994-06-19 litter 3 puppies, 3 female
Chirpy 1999-03-21 vet needed beak straightened
Slim 1997-08-03 vet broken rib
Bowser 1991-10-12 kennel
Fang 1991-10-12 kennel
Fang 1998-08-28 birthday Gave him a new chew toy
Claws 1998-03-17 birthday Gave him a new flea collar
Whistler 1998-12-09 birthday First birthday

象这样载入记录:

mysql> LOAD DATA LOCAL INFILE 'event.txt' INTO TABLE event;

以我们在pet 表上学到的查询基础,要在event表上执行查询是很简单的,因为它们的规则是一样的。 但是,如果event表自身的信息不足以回答你的问题,怎么办?

假设你想知道你的宠物是在多大年龄生小动物的,我们知道需要计算两个时间之间的差值,但是, 生小动物的时间在event 表种,但是要用来计算年龄的出生日期却在pet 表中,说明这个查询需要涉及到两个表:

mysql> SELECT pet.name,
    -> (YEAR(date)-YEAR(birth)) - (RIGHT(date,5)<RIGHT(birth,5)) AS age,
    -> remark
    -> FROM pet, event
    -> WHERE pet.name = event.name AND event.type = 'litter';
+--------+------+-----------------------------+
| name   | age  | remark                      |
+--------+------+-----------------------------+
| Fluffy |    2 | 4 kittens, 3 female, 1 male |
| Buffy  |    4 | 5 puppies, 2 female, 3 male |
| Buffy  |    5 | 3 puppies, 3 female         |
+--------+------+-----------------------------+

下面是这个查询中需要注意的事情:

  • FROM子句列出了两个表名,因为这个查询需要从两个表中提取数据。

  • 当关联 (joining) 多个表中的信息时, 你需要指定一个表中的信息是怎样和另外一个表中的信息进行匹配的,在这个例子中很简单,因为它们都有name字段, WHERE 子句使用name字段匹配两个表中的信息。

  • 由于name 列同时出现在两个表中, 所以你必须指定你引用的name列属于哪个表, 这是通过在列名前面指定表名来做到的。

你并不是必须在两个不同的表之间进行关联, 有些时候一个表也可以和它自己关联,如果你想在同一个表中把一条记录和另外一条记录进行比较,例如,要为两只动物配对,你可以让pet 表和自己关联来找出哪两只动物种类相同而性别不同:

mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
    -> FROM pet AS p1, pet AS p2
    -> WHERE p1.species = p2.species AND p1.sex = 'f' AND p2.sex = 'm';
+--------+------+--------+------+---------+
| name   | sex  | name   | sex  | species |
+--------+------+--------+------+---------+
| Fluffy | f    | Claws  | m    | cat     |
| Buffy  | f    | Fang   | m    | dog     |
| Buffy  | f    | Bowser | m    | dog     |
+--------+------+--------+------+---------+

在这个查询中,我们为这个表的两次引用分别指定了别名,这样可以明确指出哪个列名属于哪个引用。


相濡以沫,不如相忘于江湖
2006-03-02 16:10
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

3.4. 获得关于数据库和表格的信息

如果你忘记数据库或表的名字,或忘记一个给定表的结构 (例如,它的列叫什么名字),怎么办? MySQL 通过提供一些可以获取数据库和表的信息的语句来解决问题。

在前面我们看到过SHOW DATABASES语句, 该语句可以显示服务器上管理的所有数据库,如果要找出当前选择数据库,使用 DATABASE()函数:

mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| menagerie  |
+------------+

如果你没有选择任何数据库,则其结果为 NULL

要找出当前数据库中包含哪些表 (例如,你对某个表的名字不确定),使用如下命令:

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| event               |
| pet                 |
+---------------------+

如果你想知道某一个表的结构,可以使用DESCRIBE 命令,它显示表格中每一列的信息。

mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name    | varchar(20) | YES  |     | NULL    |       |
| owner   | varchar(20) | YES  |     | NULL    |       |
| species | varchar(20) | YES  |     | NULL    |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| death   | date        | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

Field 是列的名称,Type 是列的数据类型, NULL 指出该列能否包含NULL 值,Key 指出该列是否作为索引, Default 指出该列的默认值。

如果你的表格有索引,SHOW INDEX FROM tbl_name 可以得到这些索引的信息。

3.5. 在批处理模式下使用mysql

在前面的章节中, 你以输入命令和显示结果的交互模式使用 mysql,你也可以让mysql 按批处理模式工作。 要以批处理的方式运行,你必须把你要执行的命令放入一个文件,然后告诉mysql 从这个文件读取命令。

shell> mysql < batch-file

如果是在Windows下运行mysql ,并且你的文件中包含一些可能引发问题的特殊字符, 你也可以这样使用:

C:\> mysql -e "source batch-file"

如果你必须在命令行指定连接参数,命令看起来应该是这样:

shell> mysql -h host -u user -p < batch-file
Enter password: ********

如果你以这种方式使用mysql ,你还可以创建一个脚本文件,然后运行这个脚本。

如果你希望你的脚本在执行的时候即使有些命令产生错误也不中断整个脚本的执行, 应该使用--force 命令行选项。

为什么要使用脚本呢?可能有以下理由:

  • 如果你经常需要重复执行一些查询 (比如说,每天或每星期),把它写成脚本可以避免每次执行时都要输入大量命令。

  • 你可以通过复制粘贴脚本文件中的部分内容来加速新的脚本的创建。

  • 批处理模式对于不断改进你的查询语句也很有帮助,特别是对于多行的命令或者多个语句的命令序列,如果语句中出现错误,你不用全部重新输入,只需要对脚本中的错误进行修改,然后让mysql 再执行它。

  • 如果你的查询有大量的输出, 你可以使用分页的方式来查看它,这比滚动屏幕的方式要好得多。

    shell> mysql < batch-file | more
    
  • 你可以把输出结果重定向到一个文件,以便进一步处理。

    shell> mysql < batch-file > mysql.out
    
  • 你可以将脚本文件发送给别人,让别人也能执行这些命令。

  • 有些情况下不允许交互式操作,例如,以cron job(类似计划任务)的方式执行查询,这种情况下,你就必须使用批处理模式。

批处理模式下默认的输出格式和交互模式有些不同 (更加简洁) 。例如,SELECT DISTINCT species FROM pet 在交互模式下的输出看起来如下:

+---------+
| species |
+---------+
| bird    |
| cat     |
| dog     |
| hamster |
| snake   |
+---------+

而在批处理模式下,看起来却是这样:

species
bird
cat
dog
hamster
snake

如果你希望在批处理模式下得到和交互模式相同的输出格式,请使用mysql -t。 如果要回显命令本身,请使用mysql -vvv

你还可以在mysql 提示符下面使用source 或者\. 命令来执行脚本文件:

mysql> source filename;
mysql> \. filename

相濡以沫,不如相忘于江湖
2006-03-02 20:43
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

3.6. 常用示例

这里是一些例子,可以演示怎样解决MySQL中的一些常见问题。

有些示例要使用shop 表,该表中保存有每一个商人的每种货物(使用编号保存)的价格,假设每一个商人的每一种物品具有单独的价格,则 (article, dealer) 是这个记录的主键。

启动命令行工具mysql 并且选择一个数据库:

shell> mysql your-database-name

(大多数情况下,你可以使用test数据库)。

可以这样创建这个示例数据表,并向其中装入数据:

mysql> CREATE TABLE shop (
    -> article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
    -> dealer  CHAR(20)                 DEFAULT ''     NOT NULL,
    -> price   DOUBLE(16,2)             DEFAULT '0.00' NOT NULL,
    -> PRIMARY KEY(article, dealer));
mysql> INSERT INTO shop VALUES
    -> (1,'A',3.45),(1,'B',3.99),(2,'A',10.99),(3,'B',1.45),
    -> (3,'C',1.69),(3,'D',1.25),(4,'D',19.95);

执行这两个语句后,表里面应该包含如下内容:

mysql> SELECT * FROM shop;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | A      |  3.45 |
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | B      |  1.45 |
|    0003 | C      |  1.69 |
|    0003 | D      |  1.25 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

3.6.1. 查询一列的最大值

“最大的商品编号是多少?”

SELECT MAX(article) AS article FROM shop;

+---------+
| article |
+---------+
|       4 |
+---------+

3.6.2. 查询一列的最大值所在的行的数据

任务:找出最贵的商品的编号、商人和价格。

利用一个嵌套查询,这很容易做到:

SELECT article, dealer, price
FROM   shop
WHERE  price=(SELECT MAX(price) FROM shop);

另一种做法是把表中的数据按 price进行降序排列, 然后使用 MySQL-特别提供的LIMIT 子句只提取第一行数据:

SELECT article, dealer, price
FROM shop
ORDER BY price DESC
LIMIT 1;

Note: 如果表中具有多个最贵的商品, 每一个的价格都是 19.95,那么使用LIMIT 的方法就只能显示其中的一条信息。

3.6.3. 查询一列中每一组的最大值

任务:查找每一种商品的最高价格。

SELECT article, MAX(price) AS price
FROM   shop
GROUP BY article

+---------+-------+
| article | price |
+---------+-------+
|    0001 |  3.99 |
|    0002 | 10.99 |
|    0003 |  1.69 |
|    0004 | 19.95 |
+---------+-------+

3.6.4. 查询一列中每一组的最大值所在的行的数据

任务:对于每一种商品,查询最贵的那一个的编号、商人和价格信息。

这个问题可以用这样的嵌套查询解决:

SELECT article, dealer, price
FROM   shop s1
WHERE  price=(SELECT MAX(s2.price)
              FROM shop s2
              WHERE s1.article = s2.article);

3.6.5. 使用自定义变量

你可以使用 MySQL 的自定义变量来储存查询结果,而不是一定要使用客户端的临时变量来存储查询结果。(请查看Section 9.3, “User-Defined Variables”.)

例如,要查找最贵和最便宜的商品,如下:

mysql> SELECT @min_price:=MIN(price),@max_price:=MAX(price) FROM shop;
mysql> SELECT * FROM shop WHERE price=@min_price OR price=@max_price;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0003 | D      |  1.25 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

相濡以沫,不如相忘于江湖
2006-03-03 23:57
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 
呵呵,还没有翻译完呢。请耐心等待哦。

按这样的速度,我想要把这个参考手册完全翻译完,大概需要一年的时间吧。

相濡以沫,不如相忘于江湖
2006-03-04 13:04
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

3.6.6. 使用外键

在MySQL中,InnoDB 表提供对外键约束的检查。请查看Section 14.2, “The InnoDB Storage Engine”, 和 Section 1.9.5.5, “Foreign Keys”.

如果只是连接两个表,外键不是必须的。对于InnoDB以外的其它数据库引擎,也可以使用REFERENCES tbl_name(col_name) 子句来定义一个列,但是不产生任何效果, 只是当成一个备注来提示你这个字段和另外一个表中的字段有联系, 在使用这个子句的时候,认识到以下几条是非常重要的:

  • MySQL 不进行任何类型的 CHECK 以确认col_name 列一定存在于tbl_name表中 (甚至是tbl_name 表自己是否存在)。

  • 当在一个外键所在的表中进行删除行之类的操作时,MySQL 不会在引用外键的表中进行任何动作, 换句话说,这个子句无论如何没有ON DELETEON UPDATE 动作的含义。 (即使你能在REFERENCES子句中写上ON DELETEON UPDATE 子句,它们也会被忽略。)

  • 该语句创建一个 ; 但是 创建任何类型的索引或键值。

  • 如果试图定义一个InnoDB 表,该语句将产生一个错误。

你可以创建一个和另外一个列有联系的列,如下:
CREATE TABLE person (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    name CHAR(60) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE shirt (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
    color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
    owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id),
    PRIMARY KEY (id)
);

INSERT INTO person VALUES (NULL, 'Antonio Paz');

SELECT @last := LAST_INSERT_ID();

INSERT INTO shirt VALUES
(NULL, 'polo', 'blue', @last),
(NULL, 'dress', 'white', @last),
(NULL, 't-shirt', 'blue', @last);

INSERT INTO person VALUES (NULL, 'Lilliana Angelovska');

SELECT @last := LAST_INSERT_ID();

INSERT INTO shirt VALUES
(NULL, 'dress', 'orange', @last),
(NULL, 'polo', 'red', @last),
(NULL, 'dress', 'blue', @last),
(NULL, 't-shirt', 'white', @last);

SELECT * FROM person;
+----+---------------------+
| id | name                |
+----+---------------------+
|  1 | Antonio Paz         |
|  2 | Lilliana Angelovska |
+----+---------------------+

SELECT * FROM shirt;
+----+---------+--------+-------+
| id | style   | color  | owner |
+----+---------+--------+-------+
|  1 | polo    | blue   |     1 |
|  2 | dress   | white  |     1 |
|  3 | t-shirt | blue   |     1 |
|  4 | dress   | orange |     2 |
|  5 | polo    | red    |     2 |
|  6 | dress   | blue   |     2 |
|  7 | t-shirt | white  |     2 |
+----+---------+--------+-------+


SELECT s.* FROM person p, shirt s
 WHERE p.name LIKE 'Lilliana%'
   AND s.owner = p.id
   AND s.color <> 'white';

+----+-------+--------+-------+
| id | style | color  | owner |
+----+-------+--------+-------+
|  4 | dress | orange |     2 |
|  5 | polo  | red    |     2 |
|  6 | dress | blue   |     2 |
+----+-------+--------+-------+

在这种形式下,REFERENCES 并不在 SHOW CREATE TABLE 或者DESCRIBE语句的输出中显示:

SHOW CREATE TABLE shirt\G
*************************** 1. row ***************************
Table: shirt
Create Table: CREATE TABLE `shirt` (
`id` smallint(5) unsigned NOT NULL auto_increment,
`style` enum('t-shirt','polo','dress') NOT NULL,
`color` enum('red','blue','orange','white','black') NOT NULL,
`owner` smallint(5) unsigned NOT NULL,
PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

MyISAMBerkeleyDB 表中,这种方式使用的REFERENCES被当成一个注释或 “暗示” 。

3.6.7. 根据两个键查询

OR操作符对于使用一个键查询是最优化的, AND操作符也是如此。

一种特殊的情况是使用OR操作符来组合在两个键上的查询:

SELECT field1_index, field2_index FROM test_table
WHERE field1_index = '1' OR  field2_index = '1'

从MySQL 5.0.0版以后提供对这种情况的优化,请查看Section 7.2.6, “Index Merge Optimization”.

解决这个问题,还有一种有效率的办法,就是使用UNION 来联合两个 SELECT 语句的输出。请查看Section 13.2.7.2, “UNION Syntax”.

每一个SELECT 语句只从一个键查询,所有能够被优化:

SELECT field1_index, field2_index
    FROM test_table WHERE field1_index = '1'
UNION
SELECT field1_index, field2_index
    FROM test_table WHERE field2_index = '1';

3.6.8. 计算每天的访问量

下面的例子演示了怎样通过一组以bit开头的函数来计算一个月中用户有多少天访问了Web页:

CREATE TABLE t1 (year YEAR(4), month INT(2) UNSIGNED ZEROFILL,
             day INT(2) UNSIGNED ZEROFILL);
INSERT INTO t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2),
            (2000,2,23),(2000,2,23);

示例表中包含了 year-month-day 数据以指示用户访问该Web页的时间, 要知道每个月有多少天有用户访问该Web页,使用如下语句:

SELECT year,month,BIT_COUNT(BIT_OR(1<<day)) AS days FROM t1
       GROUP BY year,month;

返回结果如下:

+------+-------+------+
| year | month | days |
+------+-------+------+
| 2000 |    01 |    3 |
| 2000 |    02 |    2 |
+------+-------+------+

该查询计算每一个 year/month 组合中有多少不同的day, 重复的项将自动忽略。

3.6.9. 使用自动增量

AUTO_INCREMENT 属性可以用来自动为新增加的行产生唯一的标识。

CREATE TABLE animals (
     id MEDIUMINT NOT NULL AUTO_INCREMENT,
     name CHAR(30) NOT NULL,
     PRIMARY KEY (id)
 );

INSERT INTO animals (name) VALUES 
    ('dog'),('cat'),('penguin'),
    ('lax'),('whale'),('ostrich');

SELECT * FROM animals;

将返回:

+----+---------+
| id | name    |
+----+---------+
|  1 | dog     |
|  2 | cat     |
|  3 | penguin |
|  4 | lax     |
|  5 | whale   |
|  6 | ostrich |
+----+---------+

你可以通过LAST_INSERT_ID() SQL函数或者mysql_insert_id() C API 函数来获得最后一个 AUTO_INCREMENT 值。这些函数是独立于连接的,所以它们的返回值不会收到其它连接上插入的数据的影响。

注意: 对于多行的 insert语句,LAST_INSERT_ID()mysql_insert_id() 实际上返回这一次插入的第一行的AUTO_INCREMENT 键的值, 这允许多行插入能够在其它的replication服务器上正确的重现。

对于MyISAMBDB 表, 你可以指定多列索引中的第二列为AUTO_INCREMENT ,在这种情况下,AUTO_INCREMENT 列的值是通过 MAX(auto_increment_column) + 1 WHERE prefix=given-prefix计算的,当你想把数据放入有序群组的时候这是非常有用的。

CREATE TABLE animals (
    grp ENUM('fish','mammal','bird') NOT NULL,
    id MEDIUMINT NOT NULL AUTO_INCREMENT,
    name CHAR(30) NOT NULL,
    PRIMARY KEY (grp,id)
);

INSERT INTO animals (grp,name) VALUES 
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

将返回:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+

请注意在这种情况下 (当AUTO_INCREMENT 列为多列索引的第二列的时候),当你删除了每一组中最大的 AUTO_INCREMENT 值之后,AUTO_INCREMENT 的值是可以重用的, 在 MyISAM 表中也是如此, 正常情况下AUTO_INCREMENT 值是不可重用的。

如果AUTO_INCREMENT 列是多列索引中的一列, MySQL 将使用该列来产生自动增量。 例如,如果animals 表中包含PRIMARY KEY (grp, id)INDEX (id),MySQL 将会忽略PRIMARY KEY 以产生自动增量序列,结果就是这个表中将只包含一个序列, 而不是每一个 grp 值都有一个单独的序列。

如果要让AUTO_INCREMENT 值不是从 1开始, 你可以使用 CREATE TABLEALTER TABLE来指定该值,例如:

mysql> ALTER TABLE tbl AUTO_INCREMENT = 100;

关于AUTO_INCREMENT 的更多信息:


相濡以沫,不如相忘于江湖
2006-03-06 00:42
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

3.7. 在 Twin Project项目中查找数据

在 Analytikerna 和 Lentus,我们曾经为一个大的研究项目做过系统和现场工作。这个项目是 Karolinska Institutet Stockholm的环境医学协会 和南加里佛利亚大学的关于年龄和心理的临床研究所合作的。

这个项目先对在瑞典的所有大于65 岁的双胞胎做电话访问, 如果某对双胞胎符合某些条件,则进行下一个步骤,如果这对双胞胎愿意参与这个项目,则派出一个由医生和护士组成的小队对其进行拜访,进行一些身体或精神上的检查、实验室检查、脑电图和心理状态评估, 并且收集家族史。此外,还对医学和环境的危险度信息进行收集。

关于双胞胎研究项目的更多信息,请访问:http://www.mep.ki.se/twinreg/index_en.html

这个项目的后续部分就是使用一个使用Perl 和MySQL开发的Web接口来管理数据。

每天晚上,所有新的访问数据将被添加到 MySQL 数据库中。

3.7.1. 寻找所有未分开的双胞胎

下面的查询可以确定 哪些人可以进行这个项目的第二部分。

SELECT
    CONCAT(p1.id, p1.tvab) + 0 AS tvid,
    CONCAT(p1.christian_name, ' ', p1.surname) AS Name,
    p1.postal_code AS Code,
    p1.city AS City,
    pg.abrev AS Area,
    IF(td.participation = 'Aborted', 'A', ' ') AS A,
    p1.dead AS dead1,
    l.event AS event1,
    td.suspect AS tsuspect1,
    id.suspect AS isuspect1,
    td.severe AS tsevere1,
    id.severe AS isevere1,
    p2.dead AS dead2,
    l2.event AS event2,
    h2.nurse AS nurse2,
    h2.doctor AS doctor2,
    td2.suspect AS tsuspect2,
    id2.suspect AS isuspect2,
    td2.severe AS tsevere2,
    id2.severe AS isevere2,
    l.finish_date
FROM
    twin_project AS tp
    /* For Twin 1 */
    LEFT JOIN twin_data AS td ON tp.id = td.id
              AND tp.tvab = td.tvab
    LEFT JOIN informant_data AS id ON tp.id = id.id
              AND tp.tvab = id.tvab
    LEFT JOIN harmony AS h ON tp.id = h.id
              AND tp.tvab = h.tvab
    LEFT JOIN lentus AS l ON tp.id = l.id
              AND tp.tvab = l.tvab
    /* For Twin 2 */
    LEFT JOIN twin_data AS td2 ON p2.id = td2.id
              AND p2.tvab = td2.tvab
    LEFT JOIN informant_data AS id2 ON p2.id = id2.id
              AND p2.tvab = id2.tvab
    LEFT JOIN harmony AS h2 ON p2.id = h2.id
              AND p2.tvab = h2.tvab
    LEFT JOIN lentus AS l2 ON p2.id = l2.id
              AND p2.tvab = l2.tvab,
    person_data AS p1,
    person_data AS p2,
    postal_groups AS pg
WHERE
    /* p1 gets main twin and p2 gets his/her twin. */
    /* ptvab is a field inverted from tvab */
    p1.id = tp.id AND p1.tvab = tp.tvab AND
    p2.id = p1.id AND p2.ptvab = p1.tvab AND
    /* Just the screening survey */
    tp.survey_no = 5 AND
    /* Skip if partner died before 65 but allow emigration (dead=9) */
    (p2.dead = 0 OR p2.dead = 9 OR
     (p2.dead = 1 AND
      (p2.death_date = 0 OR
       (((TO_DAYS(p2.death_date) - TO_DAYS(p2.birthday)) / 365)
        >= 65))))
    AND
    (
    /* Twin is suspect */
    (td.future_contact = 'Yes' AND td.suspect = 2) OR
    /* Twin is suspect - Informant is Blessed */
    (td.future_contact = 'Yes' AND td.suspect = 1
                               AND id.suspect = 1) OR
    /* No twin - Informant is Blessed */
    (ISNULL(td.suspect) AND id.suspect = 1
                        AND id.future_contact = 'Yes') OR
    /* Twin broken off - Informant is Blessed */
    (td.participation = 'Aborted'
     AND id.suspect = 1 AND id.future_contact = 'Yes') OR
    /* Twin broken off - No inform - Have partner */
    (td.participation = 'Aborted' AND ISNULL(id.suspect)
                                  AND p2.dead = 0))
    AND
    l.event = 'Finished'
    /* Get at area code */
    AND SUBSTRING(p1.postal_code, 1, 2) = pg.code
    /* Not already distributed */
    AND (h.nurse IS NULL OR h.nurse=00 OR h.doctor=00)
    /* Has not refused or been aborted */
    AND NOT (h.status = 'Refused' OR h.status = 'Aborted'
    OR h.status = 'Died' OR h.status = 'Other')
ORDER BY
    tvid;

说明如下:

  • CONCAT(p1.id, p1.tvab) + 0 AS tvid

    我们希望对idtvab 连接后的结果按数值排序, 给结果加上0是为了使 MySQL 把这个结果当成数值。

  • id

    这是每一对双胞胎的标识, 在所有的表中这都是一个键。

  • tvab

    表示每一对双胞胎中的一个,它的值可以是12

  • ptvab

    这个列的值和tvab列的值相反,当tvab列的值为1时这列的值就为2, 反之亦然。这一列之所以存在是因为可以减少敲键盘的次数,还可以使 MySQL 优化查询。

在这个查询实例中,演示了怎样从到一个同样的表的连接中查找数据 (p1p2),在这里,这种技巧用来确定一对双胞胎是否在 65岁以前就死了,如果是,这一行就不返回。

上述所有信息都存在于所有表中, 我们同时使用id,tvab键 (所有表),和id,ptvab 键(person_data表) 来使查询更快。

在我们专用的机器上 (A 200MHz UltraSPARC),这个查询返回 150-200行数据,只需要不到一秒钟。

上面查询的表的当前记录是:

Table Rows
person_data 71074
lentus 5291
twin_project 5286
twin_data 2012
informant_data 663
harmony 381
postal_groups 100

3.7.2. 显示一个表示每一对双胞胎状态的表

每一次访问以一个称为event的状态码结束,这个查询用来显示一个按 event组合的所有双胞胎的表,这可以指明有多少对双胞胎的调查全部完成,有多少对双胞胎中一个完成一个没有完成,等等。

SELECT
        t1.event,
        t2.event,
        COUNT(*)
FROM
        lentus AS t1,
        lentus AS t2,
        twin_project AS tp
WHERE
        /* We are looking at one pair at a time */
        t1.id = tp.id
        AND t1.tvab=tp.tvab
        AND t1.id = t2.id
        /* Just the screening survey */
        AND tp.survey_no = 5
        /* This makes each pair only appear once */
        AND t1.tvab='1' AND t2.tvab='2'
GROUP BY
        t1.event, t2.event;

3.8. 在Apache中使用 MySQL

你可以从 MySQL 数据库中验证用户信息 ,也可以把日志写入 MySQL 表中。

你可以改变Apache的日志格式 以便于MySQL阅读,通过把下面的语句写入Apache的配置文件中:

LogFormat         "\"%h\",%{%Y%m%d%H%M%S}t,%>s,\"%b\",\"%{Content-Type}o\",          \"%U\",\"%{Referer}i\",\"%{User-Agent}i\""

要把一个日志文件按上面的格式载入到 MySQL中,你可以使用如下语句:

LOAD DATA INFILE '/local/access_log' INTO TABLE tbl_name
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'

这个表格必须先被创建,还要包含对应的列来能够容纳LogFormat 格式的数据。


相濡以沫,不如相忘于江湖
2006-03-07 21:14
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 
完整的第三章下载
uhGaUkM9.rar (29.48 KB) [翻译]MySQL5.0用户手册——第三章:快速入门



相濡以沫,不如相忘于江湖
2006-03-07 21:20
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 
我知道这样很要时间

不过我的思路和你有点不同,我不是想靠省略不重要的东西来节省时间,我是想让大家都参与进来,人多了,翻译起来就快了。

我希望我坚持下去,能够吸引足够多的参与者。我们可以让管理员创建一个门派,就叫做MySQL RMTT (即MySQL Reference Manual Traslate Team)。

相濡以沫,不如相忘于江湖
2006-03-10 19:35
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

呵呵,文中的例子我都经过亲自测试,没有问题的。


相濡以沫,不如相忘于江湖
2006-03-15 21:41
快速回复:[翻译]MySQL5.0用户手册——第三章:快速入门
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.019510 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved