Tải bản đầy đủ - 0 (trang)
Chapter 11. Generating and Using Sequences

Chapter 11. Generating and Using Sequences

Tải bản đầy đủ - 0trang

11.1 Introduction

A sequence is a set of integers 1, 2, 3, ... that are generated in order on demand. Sequences

are frequently used in databases because many applications require each row in a table to

contain a unique value, and sequences provide an easy way to generate them. This chapter

describes how to use sequences in MySQL. It covers the following topics:

Using AUTO_INCREMENT columns to create sequences.


AUTO_INCREMENT column is MySQL's mechanism for generating a sequence

over a set of rows. Each time you create a row in a table that contains an

AUTO_INCREMENT column, MySQL automatically generates the next value in the

sequence as the column's value. This value serves as a unique identifier, making

sequences an easy way to create items such as customer ID numbers, shipping

package waybill numbers, invoice or purchase order numbers, bug report IDs, ticket

numbers, or product serial numbers.

Retrieving sequence values.

For many applications, it's not enough just to create sequence values. It's also

necessary to determine the sequence value for a just-inserted record. A web

application may need to redisplay to a user the contents of a record created from the

contents of a form just submitted by the user. Or the value may need to be retrieved

so it can be stored as part of other records in a related table.

Resequencing techniques.

This section describes how to renumber a sequence that has holes in it due to record

deletions—and also discusses reasons to avoid resequencing. Other topics include

starting sequences at values other than 1 and adding a sequence column to a table

that doesn't have one.

Using an AUTO_INCREMENT column to create multiple sequences.

In many cases, the

AUTO_INCREMENT column in a table is independent of other

columns and its values increment throughout the table in a single monotonic

sequence. However, if you create a multiple-column index that contains an

AUTO_INCREMENT column, you can use it to generate multiple sequences. For

example, if you run a bulletin board that categorizes messages into topics, you can

number messages sequentially within each topic by tying an


column to a topic indicator column.

Managing multiple simultaneous AUTO_INCREMENT values.

Special care is necessary when you need to keep track of multiple sequence values.

This can occur when you issue a set of statements that affect a single table, or when

creating records in multiple tables that each have an


This section describes what to do in these cases.

Using single-row sequence generators.

Sequences also can be used as counters. For example, if you serve banner ads on

your web site, you might increment a counter for each impression (that is, for each

time you serve an ad). The counts for a given ad form a sequence, but because the

count itself is the only value of interest, there is no need to generate a new row to

record each impression. MySQL provides a solution for this problem, too, using a

mechanism that allows a sequence to be easily generated within a single table row

over time. To store multiple counters in the table, add a column that identifies the

counter uniquely. For example, you can have an arbitrary number of ad impression

counters in a table. Each row in the table identifies a specific banner ad, and the

counter in each row increments independently of the others. The same mechanism

also allows creation of sequences that increase by values other than one, by nonuniform values, or even by negative increments.

Numbering query output rows sequentially.

This section suggests ways to generate display-only sequences for the purpose of

numbering the rows of output from a query.

Sequence Generators and Portability

The engines for most database systems provide sequence generation capabilities,

though the implementations tend to be engine-dependent. That's true for MySQL as

well, so the material in this section is almost completely MySQL-specific, even at the

SQL level. In other words, the SQL for generating sequences is itself non-portable,

even if you use an API like DBI or JDBC that provides an abstraction layer. Abstract

interfaces may help you process SQL statements portably, but they don't make

nonportable SQL portable.

11.2 Using AUTO_INCREMENT To Set Up a Sequence


11.2.1 Problem

You want to include a sequence column in a table.

11.2.2 Solution

Use an


11.2.3 Discussion

This section provides the basic background on how

AUTO_INCREMENT columns work,

beginning with a short example that demonstrates the sequence-generation mechanism. The

illustration centers around a bug-collection scenario: your son (eight-year-old Junior) is

assigned the task of collecting insects for a class project at school. For each insect, Junior is to

record its name ("ant," "bee," and so forth), and its date and location of collection. You have

long expounded the benefits of MySQL for record-keeping to Junior since his early days, so

upon your arrival home from work that day, he immediately announces the necessity of

completing this project and then, looking you straight in the eye, declares that it's clearly a

task for which MySQL is well-suited. Who are you to argue? So the two of you get to work.

Junior already collected some specimens after school while waiting for you to come home and

has recorded the following information in his notebook:





stink bug

cabbage butterfly
















front yard

front yard


back yard

back yard

under rock

Looking over Junior's notes, you're pleased to see that even at his tender age he has learned

to write dates in ISO format. However, you also notice that he's collected a millipede and a

millbug, neither of which actually are insects. You decide to let this pass for the moment;

Junior forgot to bring home the written instructions for the project, so at this point it's unclear

whether or not these specimens are acceptable.

As you consider how to create a table to store this information, it's apparent that you need at


name, date, and origin columns corresponding to the types of information Junior

is required to record:









# type of insect

# date collected

# where collected

However, those columns may not be enough to make the table easy to use. Note that the

records collected thus far are not unique—both ants were collected at the same time and

place. If you put the information into an

insect table that has the preceding structure,

neither ant record can be referred to individually, because there's nothing to distinguish them

from one another. Unique IDs would be helpful to make the records distinct and to provide

values that make each record easy to refer to. An

this purpose, so a better

AUTO_INCREMENT column is good for

insect table has a structure like this:








# type of insect



# date collected


# where collected


Go ahead and create the

insect table using this second definition. Later, in Recipe 11.4,

we'll discuss the specifics of why the id column is declared the way it is.

11.3 Generating Sequence Values

11.3.1 Problem

Now that you have an

AUTO_INCREMENT column, you want to use it to generate a new

sequence value.

11.3.2 Solution


NULL into the column, or just omit it from your INSERT statement. Either way,

MySQL will create a new sequence number for you.

11.3.3 Discussion

One of the useful properties of an

AUTO_INCREMENT column is that you don't have to

assign its values yourself—MySQL does so for you. There are two ways to generate new

AUTO_INCREMENT values, demonstrated here using the id column of the insect


table. First, you can explicitly set the id column to NULL. The following statement inserts

the first four of Junior's specimens into the insect table this way:


Setting an AUTO_INCREMENT column to zero currently has the same effect as setting

it to NULL. But that is not guaranteed to be true in the future, so it's better to use NULL.

mysql> INSERT INTO insect (id,name,date,origin) VALUES

-> (NULL,'housefly','2001-09-10','kitchen'),

-> (NULL,'millipede','2001-09-10','driveway'),

-> (NULL,'grasshopper','2001-09-10','front yard'),

-> (NULL,'stink bug','2001-09-10','front yard');

Second, you can omit the

id column from the INSERT statement entirely. In MySQL, you

can create new records without explicitly specifying values for every column. MySQL assigns

default values to the missing columns automatically, and the default for an

AUTO_INCREMENT column happens to be the next sequence number. Thus, you can

insert records into the insect table without naming the id column at all. This statement

adds Junior's other four specimens to the insect table that way:






INSERT INTO insect (name,date,origin) VALUES

('cabbage butterfly','2001-09-10','garden'),

('ant','2001-09-10','back yard'),

('ant','2001-09-10','back yard'),

('millbug','2001-09-10','under rock');

Whichever method you use, MySQL determines the next sequence number for each record and

assigns it to the

id column, as you can verify for yourself:

mysql> SELECT * FROM insect ORDER BY id;


| id | name

| date

| origin



| 1 | housefly

| 2001-09-10 | kitchen


| 2 | millipede

| 2001-09-10 | driveway


| 3 | grasshopper

| 2001-09-10 | front yard |

| 4 | stink bug

| 2001-09-10 | front yard |

| 5 | cabbage butterfly | 2001-09-10 | garden


| 6 | ant

| 2001-09-10 | back yard |

| 7 | ant

| 2001-09-10 | back yard |

| 8 | millbug

| 2001-09-10 | under rock |


As Junior collects more specimens, you can add more records to the table and they'll be

assigned the next values in the sequence (9, 10, ...).

The concept underlying

AUTO_INCREMENT columns is simple enough in principle: each

time you create a new row, MySQL generates the next number in the sequence and assigns it

to the row. But there are certain subtleties to know about, as well as differences in how

AUTO_INCREMENT sequences are handled for different table types. By being aware of

these issues, you can use sequences more effectively and avoid surprises. For example, if you

explicitly set the

id column to a non-NULL value, one of two things happens:

If the value is already present in the table, an error occurs:

mysql> INSERT INTO insect (id,name,date,origin) VALUES

-> (3,'cricket','2001-09-11','basement');

ERROR 1062 at line 1: Duplicate entry '3' for key 1

This happens because when you create an

AUTO_INCREMENT column, you must

declare it to be either a PRIMARY KEY or a UNIQUE index. As a result, it cannot

contain duplicate values.

If the value is not present in the table, MySQL inserts the record using that value. In

addition, if it's larger than the current sequence counter, the table's counter is reset to

the new value plus one. The

insect table at this point has sequence values 1

through 8. If you insert a new row with the id column set to 20, that becomes the

new maximum value. Subsequent inserts that automatically generate id values will

begin at 21. The values 9 through 19 become unused, resulting in a gap in the


Now let's look in more detail at how to define

AUTO_INCREMENT columns and how they


11.4 Choosing the Type for a Sequence Column

11.4.1 Problem

You want to know more about how to define a sequence column.

11.4.2 Solution

Use the guidelines given here.

11.4.3 Discussion

You should follow certain guidelines when creating an

AUTO_INCREMENT column. As an

illustration, consider how the id column in the insect table was declared:




AUTO_INCREMENT keyword informs MySQL that it should generate successive

sequence numbers for the column's values, but the other information is important, too:

INT is the column's basic type. You need not necessarily use INT, but the column

must be one of the integer types: TINYINT, SMALLINT, MEDIUMINT, INT,

or BIGINT. It's important to remember that AUTO_INCREMENT is a column

attribute that should be applied only to integer types. Older versions of MySQL will

allow you to create an

AUTO_INCREMENT column using non-integer types such


CHAR, but bad things will happen if you do that. (Even if the initial sequence

numbers appear to be generated normally, sooner or later the column will fail. A

typical error is "duplicate key" after inserting a few records, even when you know the

column should be able to hold more numbers.) Save yourself some trouble—always

use an integer type for


The column is declared as UNSIGNED. There's no need to allow negative values,

because AUTO_INCREMENT sequences consist only of positive integers (normally

beginning at 1). Furthermore, not declaring the column to be UNSIGNED cuts the

range of your sequence in half. For example, TINYINT has a range of -128 to 127.

Sequences include only positive values, so the range of a TINYINT sequence would

be 1 to 127. The range of an unsigned TINYINT column is 0 to 255, which

increases the upper end of the sequence to 255. The maximum sequence value is

determined by the specific integer type used, so you should choose a type that is big

enough to hold the largest value you'll need. The maximum unsigned value of each

integer type is shown in the following table, which you can use to select an

appropriate type.

Column type

Maximum unsigned value











Sometimes people omit

UNSIGNED so that they can create records that contain

negative numbers in the sequence column. (Using -1 to signify "has no ID" would be

an instance of this.) MySQL makes no guarantees about how negative numbers will be

treated, so you're playing with fire if you try to use them in an

AUTO_INCREMENT column. For example, if you resequence the column, you'll

find that all your negative values get turned into regular (positive) sequence numbers.

AUTO_INCREMENT columns cannot contain NULL values, so id is declared as

NOT NULL. (It's true that you can specify NULL as the column value when you

insert a new record, but for an AUTO_INCREMENT column that really means

"generate the next sequence value.") Current versions of MySQL automatically define

AUTO_INCREMENT columns as NOT NULL if you forget to. However, it's best to

indicate NOT NULL in the CREATE TABLE statement explicitly if there is a

possibility that you might use it with an older version of MySQL sometime.

PRIMARY KEY to ensure that its values are unique.

Tables can have only one PRIMARY KEY, so if the table already has some other

PRIMARY KEY column, you can declare an AUTO_INCREMENT column to have

a UNIQUE index instead:



The column is declared as a

If the

AUTO_INCREMENT column is the only column in the PRIMARY KEY or

UNIQUE index, you can declare it as such in the column definition rather than in a

separate clause. For example, these definitions are equivalent:




As are these:




Using a separate clause to specify the index helps to emphasize that it's not, strictly

speaking, part of the column definition. (If you read through Chapter 8, you'll notice

that modifying a column's indexes is discussed separately from changing the definition

of the column itself.)

When creating a table that contains an

AUTO_INCREMENT column, it's also important to

consider the table type (MyISAM, InnoDB, and so forth). The type affects behaviors such as

reuse of values that are deleted from the top of the sequence, and whether or not you can set

the initial sequence value. In general, MyISAM is the best type for tables that contain

AUTO_INCREMENT columns, because it offers the most features for sequence

management. This will become apparent as you continue through the chapter.

11.5 The Effect of Record Deletions on Sequence


11.5.1 Problem

You want to know what happens to a sequence when you delete records from a table that

contains an


11.5.2 Solution

It depends on which records you delete and on the table type.

11.5.3 Discussion

We have thus far considered how sequence values in an


generated for circumstances where records are only added to a table. But it's unrealistic to

assume that records will never be deleted. What happens to the sequence then?

Refer again to Junior's bug-collection project, for which you currently have an

insect table

that looks like this:

mysql> SELECT * FROM insect ORDER BY id;


| id | name

| date

| origin



| 1 | housefly

| 2001-09-10 | kitchen


| 2 | millipede

| 2001-09-10 | driveway


| 3 | grasshopper

| 2001-09-10 | front yard |

| 4 | stink bug

| 2001-09-10 | front yard |

| 5 | cabbage butterfly | 2001-09-10 | garden


| 6 | ant

| 2001-09-10 | back yard |

| 7 | ant

| 2001-09-10 | back yard |

| 8 | millbug

| 2001-09-10 | under rock |


That's about to change, because after Junior remembers to bring home the written

instructions for the project, you read through them and discover two things that bear on the

insect table's contents:

Specimens should include only insects, not other insect-like creatures such as

millipedes and millbugs.

The purpose of the project is to collect as many different specimens as possible, not

just as many specimens as possible. This means that only one ant record is allowed.

These instructions require that a few rows be removed from the

those with

insect table—specifically

id values 2 (millipede), 8 (millbug), and 7 (duplicate ant). Thus, despite Junior's

evident disappointment at the reduction in the size of his collection, you instruct him to

remove those records by issuing a

DELETE statement:

mysql> DELETE FROM insect WHERE id IN (2,8,7);

This statement illustrates one reason why it's useful to have unique ID values—they allow you

to specify any record unambiguously. The ant records are identical except for the

Without that column in the


id value.

insect table, it would be more difficult to delete just one of

After the unsuitable records have been removed, the resulting table contents become:

mysql> SELECT * FROM insect ORDER BY id;


| id | name

| date

| origin



| 1 | housefly

| 2001-09-10 | kitchen


| 3 | grasshopper

| 2001-09-10 | front yard |

| 4 | stink bug

| 2001-09-10 | front yard |

| 5 | cabbage butterfly | 2001-09-10 | garden


| 6 | ant

| 2001-09-10 | back yard |


The sequence in the

id column now has a hole (row 2 is missing) and the values 7 and 8 at

the top of the sequence are no longer present. How do these deletions affect future insert

operations? What sequence number will the next new row get?

Removing row 2 created a gap in the middle of the sequence. This has no effect on

subsequent inserts, because MySQL makes no attempt to fill in holes in a sequence. On the

other hand, deleting records 7 and 8 removes values at the top of the sequence, and the

effect of this depends on the table type:

With ISAM and BDB tables, the next sequence number always is the smallest positive

integer not currently present in the column. If you delete rows containing values at the

top of the sequence, those values will be reused. (Thus, after deleting records with

values 7 and 8, the next inserted record will be assigned the value 7.)

For MyISAM or InnoDB tables, values are not reused. The next sequence number is

the smallest positive integer that has not previously been used. (For a sequence that

stands at 8, the next record gets a value of 9 even if you delete records 7 and 8 first.)

If you require strictly monotonic sequences, you should use one of these table types.

ISAM tables are the only table type available until MySQL 3.23, so prior to that version, reuse

of values deleted from the top of a sequence is the only behavior you can get. MyISAM tables

are available as of MySQL 3.23 (at which point, MyISAM also became the default table type).

BDB and InnoDB tables are available as of MySQL 3.23.17 and 3.23.29, respectively.

If you're using a table with a type that differs in value-reuse behavior from the behavior you

require, use

ALTER TABLE to change the table to a more appropriate type. For example, if

you want to change an ISAM table to be a MyISAM table (to prevent sequence values from

being reused after records are deleted), do this:




If you don't know what type a table is, use

SHOW TABLE STATUS to find out:

mysql> SHOW TABLE STATUS LIKE 'insect'\G;

*************************** 1. row ***************************


























2002-01-25 16:55:32

2002-01-25 16:55:32


The output shown here indicates that

insect is a MyISAM table. (You can also use SHOW


In this chapter, you can assume that if a table is created with no

explicit table type, it's a MyISAM table.

A special case of record deletion occurs when you clear out a table entirely using a

with no


WHERE clause:



In this case, the sequence counter may be reset to 1, even for table types for which values

normally are not reused (MyISAM and InnoDB). For those types, if you wish to delete all the

records while maintaining the current sequence value, tell MySQL to perform a record-at-atime delete by including a


WHERE clause that specifies some trivially true condition:


WHERE 1 > 0;

11.6 Retrieving Sequence Values

11.6.1 Problem

After creating a record that includes a new sequence number, you want to find out what that

number is.

11.6.2 Solution

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 11. Generating and Using Sequences

Tải bản đầy đủ ngay(0 tr)