Create Table
This is a case of practically a whole language in a single command. This command, which lets you define tables programmatically, has been tremendously enhanced in Visual FoxPro. Since it was introduced in FoxPro 2.0, CREATE TABLE has made life a lot simpler for developers. Before that, creating a table meant you had to have something to start with—usually another table with the same or similar structure to the one you wanted to create. Then you could apply COPY STRUCTURE or the pair COPY STRUCTURE EXTENDED and CREATE TABLE FROM. CREATE TABLE freed us from that nonsense.In Visual FoxPro, CREATE TABLE has whole new aspects. Not only can it create the table itself, but it can also create index tags and persistent relations. In addition, it lets you set both field-level and row-level rules and establish default values.
Usage |
CREATE TABLE | DBF TableName [ NAME LongTableName ] [ FREE ] ( FieldName1 FieldType1 [ ( nFieldWidth1 [ , nDecimals1 ] ) ] [ NULL | NOT NULL ] [ CHECK lFieldRule1 [ ERROR cFieldRuleMessage1 ] ] [ DEFAULT eDefaultExpression1 ] [ PRIMARY KEY | UNIQUE ] [ REFERENCES ReferencedTable1 [ TAG ReferencedTag1 ] ] [ NOCPTRANS ] [, FieldName2 ... ] [, PRIMARY KEY ePrimaryKeyExpression TAG PrimaryKeyTag ] [, UNIQUE eUniqueKeyExpression1 TAG UniqueKeyTag1 [, UNIQUE eUniqueKeyExpression2 ... ] ] [, FOREIGN KEY eForeignKeyExpression1 TAG ForeignKeyTag1 [ NODUP ] REFERENCES ReferencedTable2 [ TAG ReferencedTag2 ] [, FOREIGN KEY eForeignKeyExpression2 ... ] ] [, CHECK lTableRule [ ERROR cTableRuleMessage] ] ) | FROM ARRAY ArrayName |
Parameter |
Value |
Meaning |
TableName |
Name |
The filename for the new table. |
LongTableName |
Name |
The long name to give the table in the open database (128 characters max). |
FieldNamex |
Name |
The name of the xth field in the table. Long names can be used for fields of tables in databases. |
FieldTypex |
Single character |
The type to use for the xth field in the table.
Valid types are: Designate the Character (Binary) and Memo (Binary) field types seen in the Table Designer with the NOCPTRANS keyword, as shown above. |
nFieldWidthx |
Numeric |
The width of the xth field in the table. For many types, the width is fixed and nFieldWidthx should be omitted. Only Character, Numeric, and Float require field width. Cannot be specified for Double. |
nDecimalsx |
Numeric |
The number of decimal places for the xth field in the table. Relevant only for Numeric, Float, and Double. Note that for Double fields, the syntax is different than all other field types: you specify the number of decimal places in place of the field width; see the code in the Example below. |
lFieldRulex |
Logical |
A logical expression that provides the field-level rule for the xth field in the table. Can call a function. |
cFieldRuleMessagex |
Character |
The error message to display when the field rule for the xth field is violated. |
eDefaultExpressionx |
Same type as specified by FieldTypex |
An expression that provides a default value for the xth field in the table. |
ReferencedTablex |
Name |
The name of the table for which the field or expression is a foreign key. A regular index tag is created for this field or expression. |
ReferencedTagx |
Name |
The name of the tag in ReferencedTablex to which the field or expression refers. |
Omitted |
The field or expression refers to the primary key in ReferencedTablex. |
|
ePrimaryKeyExpression |
Any type |
An expression that forms the primary key for this table. Normally used when the primary key is a composite of several fields. |
PrimaryKeyTag |
Name |
The name to assign the tag created for the primary key. |
eUniqueKeyExpressionx |
Any type |
An expression that forms a candidate key for this table. Normally used for composite keys. |
UniqueKeyTagx |
Name |
The name to assign the xth candidate key tag created. |
eForeignKeyExpressionx |
Any type |
An expression that is a foreign key into another table. A regular index tag is created for this expression. Normally used for composite keys. |
ForeignKeyTagx |
Name |
The name of the tag to be created for eForeignKeyExpressionx. |
lTableRule |
Logical |
A logical expression that provides the table-level rule. Functions can be called. |
cTableRuleMessage |
Character |
The error message to display when the table-level rule is violated. |
Types of Tables
You can create two different types of tables: free tables and tables that belong to a database. Many clauses apply only when you're adding a table to a database. They are NAME, CHECK (and ERROR), DEFAULT, PRIMARY KEY, FOREIGN KEY, and REFERENCES (and TAG), at all levels where they appear. The attributes created by these clauses apply only to tables in a database. If the table is created in a database that has database events turned on, the BeforeCreateTable and AfterCreateTable events fire.The FREE keyword is needed only if there's a database set and you don't want the new table to belong to it. With no database set, free tables are created automatically.In VFP 3, to add tables to a database, the database had to be open exclusively. In VFP 5 and VFP 6, you can add tables to a shared database. Regardless, the new table is opened exclusively in an available work area.Field Information
For each field, we start out with the same information we've always had—a field name, type and size. But there's so much more here now. CREATE TABLE rightfully rejects certain VFP reserved words as field names—things like PRIMARY and FOREIGN that are just too confusing for it to deal with. Unfortunately, the Table Designer isn't as discriminating and lets you use these keywords as field names. If you're stuck with such a table and need to re-create it with code, the solution is to surround the offending field names with quotes. Of course, it would be even better if the Table Designer wouldn't let you shoot yourself in the foot this way.Fields can accept or reject nulls (poor nulls, being rejected all the time). Generally, we recommend you allow nulls only where they're meaningful—dealing with them is a pain, so don't have more than you need. SET NULL determines whether any field accepts null, unless you specify NULL or NOT NULL. Like every good rule, there's one exception: If you omit both NULL and NOT NULL, but include PRIMARY KEY or UNIQUE, the field doesn't accept nulls.NOCPTRANS determines whether codepage translation affects the field. Some kinds of data (for example, binary keys) are damaged when translated to another codepage—you can indicate which fields are badly affected. When the table is opened under another codepage, those fields are unchanged.Indexes
Several kinds of indexes can be created right along with the table. As expected, the PRIMARY KEY clause establishes a primary key for the table—one to a customer, please. The UNIQUE clause that appears at both the field and table levels has nothing to do with Xbase's traditional (and not really) unique indexes—the ones you create by SETting UNIQUE ON or adding the UNIQUE keyword to INDEX. UNIQUE in CREATE TABLE produces what's called a "candidate key"—like a primary key, no duplicates are allowed. The main difference between a primary key and a candidate key is that we've indicated that the primary key is primary. The other difference is that free tables can have candidate keys, but not primary keys.
You can't specify primary or candidate keys at the field level for fields using long names. When you try, you get the error message "Tag name is too long." That actually makes sense because the field name is used as the tag name, and tag names are still limited to 10 characters. In fact, maybe that limit is the real bug here. |
Rules
Tables in a database can have rules at both the field and table levels—that's the CHECK clause. Rules are your opportunity to make sure newly entered data is good enough for the field or table. In VFP 3, rules were not permitted to change the record. In versions starting with VFP 5, you can change the values of fields of the current record in rule code. Be careful—it's your responsibility to make sure that the changes don't result in an infinite sequence of calls to the rule code.Hip, Hip, Array!
There's an alternative to listing out all the fields with all their information. Put the data into an array (with the same structure as the ones created by AFIELDS()) and just base the table on the array. This is a great choice when you want a table that's similar, but not identical, to an existing table. Use AFIELDS() on the first table, modify the array, then CREATE TABLE from it. One caveat: Remember to change the long table name in the array (column 12 in the first row) or you may get an error message telling you that the name has already been used (for example, if you use AFIELDS() on one table in a database and use the array to create another table in the same database).Index information doesn't come along this way. When you CREATE TABLE from an array, all you get is the field structure (including rules, defaults, and so forth) and the table-level rules and triggers.Triggers
If you want to create triggers at the same time you create the table, you must create the table using an array. Otherwise, you can add triggers later with the CREATE TRIGGER command.
Example |
* Create a near duplicate of an existing table USE Original nFldCount=AFIELDS(aStruc) aStruc[1,12]="NewOne" DIMENSION aStruc(nFldCount+1,ALEN(aStruc,2)) aStruc[nFldCount+1,1]="cMyNewField" && Name aStruc[nFldCount+1,2]="C" && Type aStruc[nFldCount+1,3]=5 && Size aStruc[nFldCount+1,4]=0 && Decimals aStruc[nFldCount+1,5]=.F. && Nulls aStruc[nFldCount+1,6]=.F. && No CP aStruc[nFldCount+1,7]="JUNK" && Default aStruc[nFldCount+1,8]="" && Rule aStruc[nFldCount+1,9]="" && Error CREATE TABLE NewOne FROM ARRAY aStruc * Create a database from scratch CREATE DATABASE Clients CREATE TABLE Client ; (cClientId C(6) DEFAULT GetId("Client") ; PRIMARY KEY NOCPTRANS, ; cLastName C(20) CHECK NOT EMPTY(cLastName) ; ERROR "Must provide last name", ; cFirstName C(15), ; mStreetAddress M, ; cCity C(20), ; cState C(2) CHECK EMPTY(cState) OR ; LookUpState(cState) ; ERROR "Unknown State", ; cZip C(9), ; bCredit B(2), ; CHECK NOT (EMPTY(cState) AND NOT EMPTY(cCity)) ; ) CREATE TABLE Meetings ; (cMeetingId C(6) DEFAULT GetId("Meetings") ; PRIMARY KEY NOCPTRANS, ; dMeetingDate D, ; cClientId C(6) REFERENCES Client, ; nMeetingLength N(3) ; ) |
See Also |
AFields(), Alter Table, AfterCreateTable, BeforeCreateTable, Copy Structure, Create Cursor, Create From, Create Trigger, Index, Set NoCPTrans, Set Null |