จัดการข้อมูลเบื้องต้น (Data Base Design)

คุณคงทราบดีอยู่แล้วว่า Visual FoxPro ถูกสร้างขึ้นมาเพื่อจัดการกับฐานข้อมูล ซึ่งจะมีการเก็บข้อมูลต่างๆแล้วนำมาประมวลผล ในบทนี้เราจะมากล่าวกันเกี่ยวกัวการออกแบบฐานข้อมูล แฟ้มข้อมูล เรคอร์ด ฟิลด์ เพื่อเป็นแนวทางในการออกแบบและสร้างฐานข้อมูลต่อไป ท่านทราบหรือไม่ว่าหน่วยเก็บข้อมูลที่เล็กที่สุดของคอมพิวเตอร์คืออะไร

บิต(Bit) เป็นหน่วยเก็บข้อมูลที่เล็กที่สุดในคอมพิวเตอร์ เมื่อเรานำบิตหลายๆบิตมารวมกับก็จะเป็น ไบต์ (รหัส ASCII 8 บิต เท่ากับ 1 ไบต์) ซึ่งก็คือ 1 ตัวอักษรนั่นเอง แล้วนำตัวอักษรมารวมกันแล้วมีความหมายอย่างใดอย่างหนึ่งเราเรียกเป็นฟิลด์(Field) นำฟิลด์หลายๆฟิลด์มีมีความเกี่วยเนื่องกันมาประกอบกันรวมเป็น เรคคอร์ด(Record) หลายๆเรคคอร์รวมกันเก็บไว้ในแฟ้มข้อมูล(File) แล้วนำแฟ้มข้อมูลหลายๆแฟ้มข้อมูลมาสร้างความสัมพันธ์กันประกอบกันเป็นฐานข้อมูล ถ้าคุณต้องการที่จะสร้างระบบงานขึ้นมาใช้งานสักระบบงานหนึ่งสิ่งที่จำเป็นอย่างยิ่งก็คือ ฐานข้อมูล (Database) แล้วฐานข้อมูลมีประโยชน์อย่างไร?

1. เพื่อลดความซ้ำซ้อนของข้อมูล
2. เพื่อลดข้อผิดพลาดในการป้อนข้อมูลได้ระดับหนึ่ง
3. สามารถนำข้อมูลไปใช้ร่วมกันได้
4. ควบคุมดูแลง่าย
เป็นต้น

ผมจะขอยกตัวอย่างฐานข้อมูล ใบส่งสินค้า(Invoice) เพื่อเป็นแนวทางในการออกแบบดังต่อไปนี้ ก่อนอื่นท่านต้องมาดูก่อนว่าใบส่งสินค้านั้นประกอบไปด้วยข้อมูลอะไรบ้าง ประกอบด้วย ข้อมูลลูกค้า ข้อมูลสินค้า ข้อมูลการสั่งสินค้า เป็นต้น แล้วเรานำข้อมูลที่ได้นั้นมาออบแบบแฟ้มข้อมูล(Table) ซึ่งสามารถจำแนกออกเป็นแฟ้มข้อมูลดังตาราง

แฟ้มข้อมูลลูกค้า(Customer)

รัหสลูกค้า
CUST_ID

ชื่อ
NAME

ที่อยู่
ADDRESS

ยอดเงินคงค้าง
OUTSTNDING

วงเงินสินเชื่อ
CREDITLMT

วันให้สินเชื่อ
TERM_DAY

พนักงานขาย
SALES_ID

00001

บ.นานนานมีที 198 ถ.สาธร กทม.

150000

20000

30

S0001

00002

ร้านสะอาด 189 ถ.อิสรภาพ กทม

0

50000

60

S0001

00003

บ.สู่ความสำเร็จ 44 ถ.ร่มเกล้า กทม.

9850

7500

15

S0002

แฟ้มข้อมูลพนักงานขาย(Salesman)

รหัสพนักงานขาย
SALES_ID

ชื่อ
NAME

ที่อยู่
ADDRESS

อัตราคอมมิชชั่น
COMMRATE

S0001

นายสมหวัง 393 ถ.รามคำแหง กทม.

0.50%

S0002

นายระเบียบ 78 ซ.อ่อนนุช กทม.

0.75%

แฟ้มข้อมูลใบส่งสินค้า(Invoice)

เลขที่ใบส่งสินค้า
INV_NO

วันที่สั่ง
DATE

รหัสลูกค้า
CUST_ID

9800001

15/09/1998

00002

9800002

01/10/1998

00001

9800003

01/10/1998

00002

แฟ้มข้อมูลรายการสินค้า(Invoice Detail)

เลขที่ใบส่งสินค้า
INV_NO

รหัสสินค้า
PROD_ID

จำนวน
QUANTITY

ราคาต่อหน่วย
UNITPRICE

980001

AA001

5000

2.50

980001

BB001

850

10.00

980002

AA001

1000

2.25

98003

CC001

50

100.00

แฟ้มข้อมูลสินค้า(Product)

รหัสสินค้า
PROD_ID

ชื่อ
NAME
จำนวนคงเหลือ
ON_HAND

หน่วยนับ
UM

ราคาต่อหน่วย
UNITPRICE

AA001

น๊อต

550000

ตัว

2.50

BB001

เทปพันสายไฟ

4000

ม้วน

10.00

CC001

สี

6

กระป๋อง

110.00

ถ้าคุณพิจารณาดูแฟ้มข้อมูลตามตารางจะสังเกตเห็นว่าแฟ้มข้อมูลแต่ละแฟ้มจะมีความสัมพันธ์กับอีกแฟ้มข้อมูลหนึ่ง เช่นแฟ้มข้อมูลใบส่งสินค้า กับ แฟ้มข้อมูลลูกค้าจะมีรหัสลูกค้าเป็นตัวเชื่อมความสัมพันธ์ แล้วแฟ้มข้อมูลลูกค้า ก็จะ เชื่อมกับแฟ้มข้อมูลพนักงานขายโดยมีรหัสพนักงานขายเป็นตัวสร้างความสัมพันธ์ แล้วเมื่อไหร่เราต้องทำการสร้างความสัมพันธ์ระหว่างแฟ้มข้อมูล? อันดับแรกในการสร้างความสัมพันธ์(relation) เราต้องคำนึ่งถึงความซ้ำซ้อนข้องข้อมูล เช่นในใบส่งสินค้า จะประกอบไปด้วยข้อมูลลูกค้า ถ้าลูกค้ารายนั้นๆทำการสั่งสินค้าเสมอ เมื่อเราทำการออกใบส่งสินค้าให้ ทุกครั้งเราต้องมาทำการป้อนข้อมูลลูกค้ารายนั้นอีก ซึ่งข้อมูลที่ป้อนจะมีลักษณะเหมือนกันทุกครั้งไป ดังนั้นเรา จำเป็นต้องสร้างแฟ้มข้อมูลลูกค้าเพื่อมารองรับในส่วนนี้ แล้วจัดการเชื่อมแฟ้มข้อมูลทั้งสองแฟ้มด้วยรหัส ซึ่งการเชื่อมนี้เราเรียกว่าการสร้างความสัมพันธ์ เมื่อแฟ้มข้อมูลมีการสร้างความสัมพันธ์ขึ้นมาก็เกิดเป็น ฐานข้อมูลขึ้น

แล้วใน Visual FoxPro จะสร้างฐานข้อมูลขึ้นมาได้อย่างไร?
ในบทที่ผ่านมาผมได้กล่างถึงคำสั่งที่ใช้สร้าง แฟ้มข้อมูล(Table) ไว้แล้ว ที่นี้เราจะมาทำการสร้าง แฟ้มข้อมูลขึ้นมาตามตัวอย่างในตารางข้างต้น
ให้ทำการสร้างโปรแกรมเพื่อทำการสร้าง ฐานข้อมูล (Database)
ทำการพิมพ์คำสั่งผ่านทาง Command Window โดยพิมพ์ คำสั่ง
MODIFY COMMAND GenStru แล้วกดปุ่ม Enter
แล้ว็ทำการป้อนคำสั่งต่อไปนี้

*GenStru.PRG
* Create Database File
CREATE DATABASE myDatabase
* Create Database Table
CREATE TABLE Salesman (Sales_ID c(5) PRIMARY KEY, ;
Name c(60),Address c(120),CommRate n(5,2))
CREATE TABLE Customer (Cust_ID c(5) PRIMARY KEY,;
Name c(60),Address c(120),Creditlmt n(3,0), ;
Term_day n(3,0), Sales_ID c(5), ;
FOREIGN KEY Sales_ID TAG Sales_ID REFERENCE Salesman)
CREATE TABLE Product (Prod_ID c(5) PRIMARY KEY, ;
Name c(60),On_Hand n(7,0),UM c(10),UnitPrice n(10,2))
CREATE TABLE Inv_Head (Inv_NO n(6,0) PRIMARY KEY, ;
Date d(8),Cust_ID c(5), ;
FOREIGN KEY Cust_ID TAG Cust_ID REFERENCE Customer)
CREATE TABLE Inv_Dtl (Inv_NO n(6,0),Prod_ID c(5), ;
Quantity n(6,0),UnitPrice n(10,2), ;
FOREIGN KEY Inv_NO TAG Inv_NO REFERENCE Inv_Head ,;
FOREIGN KEY Prod_ID TAG Prod_ID REFERENCE Product)

หรือ

*GenStru.PRG
CREATE DATABASE ‘MYDATABASE.DBC’
***** Table setup for SALESMAN *****
CREATE TABLE ‘SALESMAN’ (SALES_ID C(5) NOT NULL, ;
NAME C(60) NOT NULL, ;
ADDRESS C(120) NOT NULL, ;
COMMRATE N(5, 2) NOT NULL)
***** Create each index for SALESMAN *****
ALTER TABLE ‘SALESMAN’ ADD PRIMARY KEY SALES_ID TAG SALES_ID
***** Change properties (if any) for SALESMAN *****
***** Table setup for CUSTOMER *****
CREATE TABLE ‘CUSTOMER’ (CUST_ID C(5) NOT NULL, ;
NAME C(60) NOT NULL, ;
ADDRESS C(120) NOT NULL, ;
CREDITLMT N(3, 0) NOT NULL, ;
TERM_DAY N(3, 0) NOT NULL, ;
SALES_ID C(5) NOT NULL)
***** Create each index for CUSTOMER *****
ALTER TABLE ‘CUSTOMER’ ADD PRIMARY KEY CUST_ID TAG CUST_ID
INDEX ON SALES_ID TAG SALES_ID
***** Change properties (if any) for CUSTOMER *****
***** Table setup for PRODUCT *****
CREATE TABLE ‘PRODUCT’ (PROD_ID C(5) NOT NULL, ;
NAME C(60) NOT NULL, ;
ON_HAND N(7, 0) NOT NULL, ;
UM C(10) NOT NULL, ;
UNITPRICE N(10, 2) NOT NULL)
***** Create each index for PRODUCT *****
ALTER TABLE ‘PRODUCT’ ADD PRIMARY KEY PROD_ID TAG PROD_ID
***** Change properties (if any) for PRODUCT *****
***** Table setup for INV_HEAD *****
CREATE TABLE ‘INV_HEAD’ (INV_NO N(6, 0) NOT NULL, ;
DATE D NOT NULL, ;
CUST_ID C(5) NOT NULL)
***** Create each index for INV_HEAD *****
ALTER TABLE ‘INV_HEAD’ ADD PRIMARY KEY INV_NO TAG INV_NO
INDEX ON CUST_ID TAG CUST_ID
***** Change properties (if any) for INV_HEAD *****
***** Table setup for INV_DTL *****
CREATE TABLE ‘INV_DTL’ (INV_NO N(6, 0) NOT NULL, ;
PROD_ID C(5) NOT NULL, ;
QUANTITY N(6, 0) NOT NULL, ;
UNITPRICE N(10, 2) NOT NULL)
***** Create each index for INV_DTL *****
INDEX ON INV_NO TAG INV_NO
INDEX ON PROD_ID TAG PROD_ID
***** Change properties (if any) for INV_DTL *****
*************** Begin Relations Setup **************
ALTER TABLE ‘CUSTOMER’ ADD FOREIGN KEY TAG SALES_ID REFERENCES SALESMAN TAG SALES_ID
ALTER TABLE ‘INV_HEAD’ ADD FOREIGN KEY TAG CUST_ID REFERENCES CUSTOMER TAG CUST_ID
ALTER TABLE ‘INV_DTL’ ADD FOREIGN KEY TAG INV_NO REFERENCES INV_HEAD TAG INV_NO
ALTER TABLE ‘INV_DTL’ ADD FOREIGN KEY TAG PROD_ID REFERENCES PRODUCT TAG PROD_ID

เมื่อป้อนเสร็จให้ทำการ Save โดยกด Ctrl+W แล้วพิมพ์คำสั่ง DO GenStru ที่ Command Windows
โปรแกรมก็จะทำการสร้างฐานข้อมูลชื่อ myDatabase ขึ้นมาให้อัตโนมัติ จากนั้นให้พิมพ์คำสั่ง
CLOSE DATABASE
MODIFY DATABASE myDatabase
แล้วดูว่ามีอะไรเกิดขึ้นบ้าง

เคล็ดไม่ลับ  ถ้าคุณมีแฟ้ม Database อยู่แล้วคุณสามารถแปลงกลับมาเป็น .PRG ได้โดยใช้คำสั่ง  DO HOME()+’\TOOLS\GENDBC\GENDBC.PRG’

จริงๆแล้วในการสร้างฐานข้อมูลใน Visual FoxPro นั้นมีวิธีการสร้างหลายวิธี ที่ผมอธิบายมานี้ก็เป็น อีกวิธีหนึ่งในการสร้าง แต่ที่ผมสร้างเป็นโปรแกรมไว้นี้ต่อๆไปเราจะนำไปใช้งานกันอีก คงมีหลายท่านสงสัยว่าเมื่อสร้างเสร็จแล้วก็แล้วกันทำไมต้องเขียนเป็นโปรแกรมให้ยุ่งยาก เหตุผลของผมหรือวิธีการของผมนั้นมีเอาไว้เพื่อ         ถ้าแฟ้มข้อมูลของคุณบังเอิญถูกลบหมดแล้วคุณจำโครงสร้างของแฟ้มข้อมูลไม่ได้ คุณสามารถนำมันไปสร้างฐานข้อมูลขึ้นมาใหม่ได้
เมื่อคุณนำโปรแกรมไปแจกจ่าย (Compile เป็น .exe แล้วคุณไม่จำเป็นต้อง Copy แฟ้มข้อมูลไปด้วยเพียงแต่คุณทำการเขียนโปรแกรมให้มันไปเรียก โปรแกรม GenStru ขึ้นมามันก็จะทำการสร้างฐานข้อมูลให้คุณ ส่วนวิธีการนำไปใช้นั้นตอนสร้าง ระบบงานผมจะอธิบายอีกครั้ง ขอย้ำนี้เป็นเพียงแนวความคิดส่วนตัวมิได้ห้ามเลียนแบบ
ตอนนี้เรามาดูรายละเอียดและคำสั่งต่างๆเกี่ยวกับ ฐานข้อมูล และ แฟ้มข้อมูล กันก่อน
ใน Visual FoxPro ได้แยกแฟ้มข้อมูลออกเป็น 2 ชนิด  คือ Free Table กับ Database Table  จริงๆแล้วมันก็คือแฟ้มตัวเดียวกันมีนามสกุลเป็น  .DBF แล้วมันต่างกันอย่างไร?
Free Table คือแฟ้มข้อมูล .DBF ที่ไม่ผูกอยู่กับ  แฟ้ม Database คุณสามารถทำการเปิดแฟ้มนี้หรือเพิ่มแฟ้มนี้เข้าไปใน แฟ้ม Database ใดก็ได้
Database Table คือแฟ้มข้อมูล .DBF ที่ไปผูกอยู่กับ แฟ้ม Database เมื่อนำไปใช้งานจะต้องเปิดพร้อมกับ Database File
แล้วทำไมต้องสร้าง Database file เพื่อมาผูกกับ Database Table ด้วย
เหตุผลหลักเลยก็คือทำให้คุณสามารถเห็นความสัมพันธ์ระหว่างแฟ้มข้อมูลซึ่งก็เข้าหลักของระบบฐานข้อมูล
และคุณสามารถตั้งชื่อ Database Table ตั้งชื่อ Field ได้ยาวขึ้น ถึง 128 ตัวอักษร ซึ่ง แฟ้ม .DBF เดิมตั้งชื่อ แฟ้มได้ 8 ตัว ชื่อ Field ได้ 10 ตัวอักษร
คำสั่งต่างเกี่ยวกับฐานข้อมูล
สร้างฐานข้อมูล (แฟ้ม .DBC)

 CREATE DATABASE [DatabaseName | ?]

เช่น        CREATE DATABASE myDatabase

สร้าง Table (แฟ้ม .DBF)

CREATE TABLE | DBF TableName1 [NAME LongTableName] [FREE]
(FieldName1 FieldType [(nFieldWidth [, nPrecision])]
[NULL | NOT NULL]
[CHECK lExpression1 [ERROR cMessageText1]]
[DEFAULT eExpression1]
[PRIMARY KEY | UNIQUE]
[REFERENCES TableName2 [TAG TagName1]]
[NOCPTRANS]
[, FieldName2 …]
[, PRIMARY KEY eExpression2 TAG TagName2
|, UNIQUE eExpression3 TAG TagName3]
[, FOREIGN KEY eExpression4 TAG TagName4 [NODUP]
REFERENCES TableName3 [TAG TagName5]]
[, CHECK lExpression2 [ERROR cMessageText2]])
| FROM ARRAY ArrayName

เช่น       CREATE TABLE Customer (Cust_ID c(5) PRIMARY KEY,;
Name c(60),Address c(120),Creditlmt n(3,0), ;
Term_day n(3,0), Sales_ID c(5), ;
FOREIGN KEY Sales_ID TAG Sales_ID REFERENCE Salesman)

จากตัวอย่างข้างต้นจะเป็นการสร้าง database table พร้อมๆกับ สร้างแฟ้มดัชนี (ถ้ามีการเปิด database file อยู่ก่อนแล้วเมื่อเราทำการสร้าง table โปรแกรมจะถือว่าเป็นการสร้าง database table โดยอัตโนมัติ)

** ขอย้ำตอนนี้คุณสามารถกำหนดชื่อฟิลด์ได้ยาวถึง 128 ตัวน๊ะจะบอกให้

ใน Visual FoxPro จะมีแฟ้มดัชนีอยู่ 2 ประเภทคือ Structure Compound Compact  Index (.CDX) และ Single-key (.IDX) ทั้งสองประเภทมีความแตกต่างกันอย่างไรและเราควรใช้แฟ้มดัชนีแบบไหน

Single-key Index

Structural Compound  Compact Index

จำนวนดัชนีต่อ 1 แฟ้มข้อมูล 1 ดัชนี มากกว่า 1 ดัชนี
ความยาวของดัชนี 100 ตัวอัษร 240 ตัวอัษร
การเปิดแฟ้มดัชนี ต้องทำการเปิดเองโดยใช้คำสั่ง set index to file.idx จะทำการเปิดให้อัตโนมัติพร้อมกับการเปิด table
การเรียกใช้ดัชนี เรียกจากแฟ้มดัชนี เรียกจาก tag name

จากตารางข้างต้นคงจะสรุปได้ว่าเราควรใช้แฟ้มดัชนีแบบไหน ถ้าเป็นผมจะขอใช้ .CDX

มีวิธีอื่นอีกหรือไม่ที่จะทำการสร้างแฟ้มดัชนี ? เราสามารถสร้าแฟ้มดัชนี้ได้โดยใช้คำสั่ง

INDEX ON eExpression TO IDXFileName | TAG TagName [OF CDXFileName]
[FOR lExpression]
[COMPACT]
[ASCENDING | DESCENDING]
[UNIQUE | CANDIDATE]
[ADDITIVE]

จากคำสั่งข้างต้นถ้าเราใส่ key word IDXFileName โปรแกรมจะทำการสร้างแฟ้มดัชนีเป็นแบบ Single-key index ให้ แต่ถ้าเราไม่ใส่ ก็จะเป็น Structural Compound Compact Index แทน

เช่น         INDEX ON CUST_ID TAG CUST_ID
INDEX ON SUBST(NAME,1,1) TAG NAME

เคล็ดไม่ลับ  คุณสามารถ ขอดู tag name ได้โดยใช้คำสั่ง ?tag(1)
ถ้าต้องการดูว่าดัชนีที่เราทำการจัดเรียงมีการเขียนประโยคว่าอย่างไรให้ใช้ ?sys(14,1)
(1 คือลำดับในการทำ index ถ้ามีหลาย tag  tag ตัวต่อไปก็จะเป็นเลข 2,3 .. ไปเรื่อยๆ)

การเรียกดัชนีมาใช้งานนั้นถ้าเป็นแบบ compound index เราต้องบอกให้โปรแกรมทราบว่าเราจะนำ tag ใดมาใช้งานเพราะว่าการเปิด table มาใช้งานนั้นโปรแกรมจะทำการเปิด แฟ้มดัชนีขึ้นมาให้อัตโนมัติอยู่แล้ว แต่การจะเลือกใช้ว่าจะใช้ tag ตัวใหนเราต้องเป็นผู้กำหนด โดยใช้คำสั่ง

SET ORDER TO
[nIndexNumber | IDXIndexFileName | [TAG] TagName [OF CDXFileName]
[IN nWorkArea | cTableAlias]
[ASCENDING | DESCENDING]]

เช่น             SET ORDER TO 1
SET ORDER TO TAG NAME
SET ORDER TO TAG SALES_ID

หรือเราสามารถเรียกดัชนีมาพร้อมกับการเปิดแฟ้มข้อมูลขึ้นมาก็ได้ โดยใช้คำสั่ง USE

USE SALESMAN ORDER 1
USE SALESMAN TAG SALES_ID

ถึงตอนนี้เราลองมาดูตัวอย่างโปรแกรมป้อนข้อมูลกันเล่นๆซักตัวอย่างแก้เซ็งกันก่อนแล้วค่อยว่ากันต่อ ให้คุณสร้างโปรแกรมชื่อ program4.prg ทำการป้อนตามตัวอย่างด้านล่างแล้วลองเรียกโปรแกรมนี้ดูว่าเป็นอย่างไร

อ๊ะๆ จะเรียกโปรแกรมใช้คำสั่ง  do program4 ที่ command window น๊ะจ๊ะ

* program4.prg
PUBLIC oform1
ON SHUTDOWN DO PRGERR && When program error click X (close foxpro) botton
SET DELETE ON
IF !USED(‘SALESMAN’)
select 0
use Salesman
ENDIF
SET ORDER TO TAG SALES_ID
GO TOP
SCATTER MEMVAR
oform1=CREATEOBJECT(“form1”)
oform1.Show()
oform1.cmdGroup.oTop.Enabled=.F.
oform1.cmdGroup.oPrev.Enabled=.F.
if reccount() = 0
oform1.cmdGroup.oNext.Enabled=.F.
oform1.cmdGroup.oBott.Enabled=.F.
endif
READ EVENT
RETURN

DEFINE CLASS form1 AS form
Height = 261
Width = 633
DoCreate = .T.
AutoCenter = .T.
Caption = “Salesman”
ControlBox = .F.
LockScreen = .F.
Name = “Form1”

ADD OBJECT osales_id AS textbox WITH ;
ControlSource = “m.sales_id”, ;
Enabled = .F., ;
Height = 24, ;
Left = 132, ;
Top = 24, ;
Width = 73, ;
Name = “oSales_id”

ADD OBJECT oname AS textbox WITH ;
ControlSource = “m.name”, ;
Enabled = .F., ;
Height = 24, ;
Left = 132, ;
Top = 60, ;
Width = 265, ;
Name = “oName”

ADD OBJECT oaddress AS textbox WITH ;
ControlSource = “m.address”, ;
Enabled = .F., ;
Height = 24, ;
Left = 132, ;
Top = 96, ;
Width = 456, ;
Name = “oAddress”

ADD OBJECT ocommrate AS textbox WITH ;
Alignment = 3, ;
Value = 0, ;
ControlSource = “m.commrate”, ;
Enabled = .F., ;
Format = “R”, ;
Height = 24, ;
InputMask = “999.99”, ;
Left = 132, ;
Top = 132, ;
Width = 61, ;
Name = “oCommrate”

ADD OBJECT cmdgroup AS commandgroup WITH ;
ButtonCount = 8, ;
Value = 1, ;
Height = 39, ;
Left = 12, ;
Top = 192, ;
Width = 615, ;
Name = “cmdGroup”, ;
Command1.Top = 5, ;
Command1.Left = 5, ;
Command1.Height = 29, ;
Command1.Width = 73, ;
Command1.Caption = “Top”, ;
Command1.Name = “oTop”, ;
Command2.AutoSize = .F., ;
Command2.Top = 5, ;
Command2.Left = 81, ;
Command2.Height = 29, ;
Command2.Width = 73, ;
Command2.Caption = “Previous”, ;
Command2.Name = “oPrev”, ;
Command3.Top = 5, ;
Command3.Left = 157, ;
Command3.Height = 29, ;
Command3.Width = 73, ;
Command3.Caption = “Next”, ;
Command3.Name = “oNext”, ;
Command4.Top = 5, ;
Command4.Left = 233, ;
Command4.Height = 29, ;
Command4.Width = 73, ;
Command4.Caption = “Bottom”, ;
Command4.Name = “oBott”, ;
Command5.AutoSize = .F., ;
Command5.Top = 5, ;
Command5.Left = 309, ;
Command5.Height = 29, ;
Command5.Width = 73, ;
Command5.Caption = “New”, ;
Command5.Name = “oNew”, ;
Command6.Top = 5, ;
Command6.Left = 385, ;
Command6.Height = 29, ;
Command6.Width = 73, ;
Command6.Caption = “Change”, ;
Command6.Name = “oChge”, ;
Command7.Top = 5, ;
Command7.Left = 461, ;
Command7.Height = 29, ;
Command7.Width = 73, ;
Command7.Caption = “Delete”, ;
Command7.Name = “oDele”, ;
Command8.Top = 5, ;
Command8.Left = 537, ;
Command8.Height = 29, ;
Command8.Width = 73, ;
Command8.Caption = “Exit”, ;
Command8.Name = “oExit”

ADD OBJECT label1 AS label WITH ;
Caption = “Salesman No.”, ;
Height = 18, ;
Left = 24, ;
Top = 24, ;
Width = 88, ;
Name = “Label1”

ADD OBJECT label2 AS label WITH ;
Caption = “Name”, ;
Height = 18, ;
Left = 75, ;
Top = 60, ;
Width = 37, ;
Name = “Label2”

ADD OBJECT label3 AS label WITH ;
Caption = “Address”, ;
Height = 18, ;
Left = 62, ;
Top = 96, ;
Width = 50, ;
Name = “Label3”

ADD OBJECT label4 AS label WITH ;
Caption = “Commission”, ;
Height = 18, ;
Left = 35, ;
Top = 132, ;
Width = 77, ;
Name = “Label4”

PROCEDURE cmdgroup.oTop.Click
if !bof()
go top
scatt memvar
this.enabled=.F.
this.parent.oPrev.enabled=.F.
this.parent.oNext.enabled=.T.
this.parent.oBott.enabled=.T.
endif
thisform.refresh
ENDPROC

PROCEDURE cmdgroup.oPrev.Click
if !bof()
skip -1
if bof()
go top
this.parent.oTop.enabled=.f.
this.enabled=.f.
endif
scatt memvar
this.parent.oNext.enabled=.T.
this.parent.oBott.enabled=.T.
endif
thisform.refresh
ENDPROC

PROCEDURE cmdgroup.oNext.Click
if !eof()
skip
if eof()
go bott
this.enabled=.F.
this.parent.oBott.enabled=.F.
endif
scatt memvar
this.parent.oTop.enabled=.T.
this.parent.oPrev.enabled=.T.
endif
thisform.refresh
ENDPROC

PROCEDURE cmdgroup.oBott.Click
if !eof()
go bott
scatt memvar
this.enabled=.F.
this.parent.oNext.enabled=.F.
this.parent.oTop.enabled=.T.
this.parent.oPrev.enabled=.T.
endif
thisform.refresh
ENDPROC

PROCEDURE cmdgroup.oNew.Click
if this.caption = ‘New’
scat memvar blank
thisform.oSales_id.Enabled = .T.
thisform.oName.Enabled = .T.
thisform.oAddress.Enabled = .T.
thisform.oCommrate.Enabled = .T.
this.caption = ‘Save’
this.parent.oChge.caption = ‘Cancel’
this.parent.oTop.Enabled = .F.
this.parent.oPrev.Enabled = .F.
this.parent.oBott.Enabled = .F.
this.parent.oNext.Enabled = .F.
this.parent.oDele.Enabled = .F.
this.parent.oExit.Enabled = .F.
else
do case
case this.caption = ‘Save’ .and. this.parent.oChge.caption = ‘Cancel’
if !empty(thisform.oSales_id.value)
INSERT INTO Salesman FROM MEMVAR
else
wait window ‘Sales_id must be Entry! Program not save’
endif
case this.caption = ‘Save’ .and. this.parent.oChge.caption = ‘Reverse’
GATHER MEMVAR
endcase
thisform.oSales_id.Enabled = .F.
thisform.oName.Enabled = .F.
thisform.oAddress.Enabled = .F.
thisform.oCommrate.Enabled = .F.
this.caption = ‘New’
this.parent.oChge.caption = ‘Change’
this.parent.oTop.Enabled = .T.
this.parent.oPrev.Enabled = .T.
this.parent.oBott.Enabled = .T.
this.parent.oNext.Enabled = .T.
this.parent.oDele.Enabled = .T.
this.parent.oExit.Enabled = .T.
endif
thisform.refresh
ENDPROC

PROCEDURE cmdgroup.oChge.Click
if recc() = 0 .and. this.parent.oChge.caption = ‘Change’
wait wind ‘No data cannot change this record’
else
if this.caption = ‘Change’
thisform.oSales_id.Enabled = .T.
thisform.oName.Enabled = .T.
thisform.oAddress.Enabled = .T.
thisform.oCommrate.Enabled = .T.
this.caption = ‘Reverse’
this.parent.oNew.caption = ‘Save’
this.parent.oTop.Enabled = .F.
this.parent.oPrev.Enabled = .F.
this.parent.oBott.Enabled = .F.
this.parent.oNext.Enabled = .F.
this.parent.oDele.Enabled = .F.
this.parent.oExit.Enabled = .F.
else
do case
case this.caption = ‘Reverse’
scatter memvar
case this.caption = ‘Cancel’ && for addnew record
go bott
scatter memvar
endcase
thisform.oSales_id.Enabled = .F.
thisform.oName.Enabled = .F.
thisform.oAddress.Enabled = .F.
thisform.oCommrate.Enabled = .F.
this.caption = ‘Change’
this.parent.oNew.caption = ‘New’
this.parent.oTop.Enabled = .T.
this.parent.oPrev.Enabled = .T.
this.parent.oBott.Enabled = .T.
this.parent.oNext.Enabled = .T.
this.parent.oDele.Enabled = .T.
this.parent.oExit.Enabled = .T.
endif
endif
thisform.refresh
ENDPROC

PROCEDURE cmdgroup.oDele.Click
if recc() = 0
wait wind ‘No data cannot delete this record’
else
nAnswer = MESSAGEBOX(‘Confirm Delete’, 4 + 32 + 256,’Delete Record’)
DO CASE
CASE nAnswer = 6
Delete
go bott
scatt memvar
CASE nAnswer = 7
* not Delete
ENDCASE
endif
Thisform.refresh
ENDPROC

PROCEDURE cmdgroup.oExit.Click
USE
SET DELETE OFF
thisform.release
CLEAR EVENT
on shutdown
ENDPROC
ENDDEFINE

PROCEDURE PRGERR
CLEAR EVENT
close all
clear all
on shutdown
ENDPROC

ตัวอย่างที่ให้มานี้เป็นตัวอย่างการป้อนข้อมูลของ Salesman ก็ลองทำการป้อนข้อมูลเล่นๆไปสัก 4-5 คนก่อน แล้วเราจะมาต่อกันในบทต่อไปเรื่องจัดการข้อมูลภาคสอง