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.

The



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



AUTO_INCREMENT



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



AUTO_INCREMENT column.



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

Column

11.2.1 Problem

You want to include a sequence column in a table.



11.2.2 Solution



Use an



AUTO_INCREMENT column.



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:



Name

millipede

housefly

grasshopper

stink bug

cabbage butterfly

ant

ant

millbug



Date

2001-09-10

2001-09-10

2001-09-10

2001-09-10

2001-09-10

2001-09-10

2001-09-10

2001-09-10



Origin

driveway

kitchen

front yard

front yard

garden

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

least



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



is required to record:



CREATE TABLE insect

(

name

VARCHAR(30) NOT NULL,

date

DATE NOT NULL,

origin VARCHAR(30) NOT NULL

);



# 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:



CREATE TABLE insect

(

id

INT UNSIGNED NOT NULL AUTO_INCREMENT,

PRIMARY KEY (id),

name

VARCHAR(30) NOT NULL,

# type of insect

date

DATE NOT NULL,

# date collected

origin VARCHAR(30) NOT NULL

# 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

Insert



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

[1]

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:

[1]



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:

mysql>

->

->

->

->



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

sequence.

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



AUTO_INCREMENT columns and how they



behave.



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:

id INT UNSIGNED NOT NULL AUTO_INCREMENT,

PRIMARY KEY (id)

The



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



as



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







AUTO_INCREMENT columns.

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



TINYINT



255



SMALLINT



65,535



MEDIUMINT



16,777,215



INT



4,294,967,295



BIGINT



18,446,744,073,709,551,615



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:







id INT UNSIGNED NOT NULL AUTO_INCREMENT,

UNIQUE (id)



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:



id INT UNSIGNED NOT NULL AUTO_INCREMENT,

PRIMARY KEY (id)

id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY

As are these:



id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE

id INT UNSIGNED NOT NULL AUTO_INCREMENT,

UNIQUE (id)

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

Generation

11.5.1 Problem

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

contains an



AUTO_INCREMENT column.



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



AUTO_INCREMENT column are



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

them.



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:



ALTER TABLE



tbl_name



TYPE = MYISAM;



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 ***************************



Name:

Type:

Row_format:

Rows:

Avg_row_length:

Data_length:

Max_data_length:

Index_length:

Data_free:

Auto_increment:

Create_time:

Update_time:

Check_time:

Create_options:

Comment:



insect

MyISAM

Dynamic

7

30

216

4294967295

2048

0

8

2002-01-25 16:55:32

2002-01-25 16:55:32

NULL



The output shown here indicates that



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



CREATE TABLE.)

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



DELETE



WHERE clause:



DELETE FROM



tbl_name;



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



DELETE FROM



WHERE clause that specifies some trivially true condition:



tbl_name



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)

×