วันพุธที่ 22 มกราคม พ.ศ. 2557

DB2 กับ RPG ภาค2

ผู้ที่ระบบที่ใช้ต่อเนื่องมานาน เกิน 15 ปี
น่าจะพบปัญหาเดียวกันนี้น๊ะครับ

Q1: Physical File = สร้างโดยไม่ระบุ Primary Key (Unique)

    แล้วจะรู้ได้อย่างไรว่า  Primary Key คือ อะไร ?
    การ Insert/Update/Delete จะชี้ได้ถูกต้อง อย่างไร ?

A1: ถ้าระบบฯ  มีอยู่แล้ว
    - เชื่อว่า โปรแกรม Maintenance ดั้งเดิม  ทำงานถูก  ได้ช่วยไกด์เรา
    - ตรวจสอบซ้ำ (จากตัว data)

SQL :  Select   Primary Keys  ,count(*) From Lib.File    
      Group by Primary Keys     
      Having   count(*) > 1

ถ้ามี  rows ออกมา  แสดงว่า  Primary Keys ไม่ถูกต้อง

อธิบาย
- Primary Keys (มีมากกว่า 1 Field ได้)
- ตามนิยาม เมื่อชี้ข้อมูลด้วย  Primary Keys จะพบแค่ 1 row เท่านั้น
- หลังการ  กรองค่า (Having)  ถ้า Primary Keys ถูกต้อง  ต้องไม่มี rows แสดงออกมา

อืนๆ - บางที่  จะมีการเก็บ ข้อมูลที่ "ลบ" ไว้ใน File  (ทำให้  ข้อมูลกลุ่มนี้  ไม่เป็นไปตามกฏ)
ดังนั้น ต้องแยกข้อมูลกลุ่มนี้  ออกไปก่อน  
เช่น itemNo ถ้าลบ จะใส่  "#" นำหน้า  ป้อนแล้วลบ  2 ครั้ง  จะมีรายการนี้ซ้ำ 2 รายการ

    - ตรวจจาก Business Concept
      เช่น   Stock File  (ItemNo, ItemName, WH , Loca, Vendor, OnHandQty)
               นิยามว่า   ItemNo  จัดวางอยู่ที่  พื้นที่ (WH,Loca)
               Primary Keys = ItemNo, WH(WareHouse),Loca

               นิยามว่า   ItemNo  จัดวางอยู่ที่  พื้นที่ (WH,Loca)  โดยต้องแสดงแยกตาม Vendor
               Primary Keys = ItemNo, WH(WareHouse),Loca, Vendor

               >> จะเห็นว่า  ถ้าใครโชคดี  ใช้ DB ที่มีโครงสร้างสมบุรณ์  (มี Field มาก)
แต่ไม่ได้กำหนด Primary Key ไว้   สามารถเดา  "ได้หลากหลาย"

Q2: ทำไม สร้าง Field ใน Logical File เหมือนใน Physical File

       สร้างแตกต่าง  ระดับ Field ได้หรือไม่ ?
A2: ได้ครับ
       ดั้งเดิม  เราจะทำให้มัน  เข้าใจ(จำ)ง่าย - เป็นเทคนิคที่ดีสำหรับระบบขนาดใหญ่
       แต่ระบบ DB ปัจจุบัน  ที่สอนกัน (จนเป็นมาตรฐาน)
       แยกเรียก Logical File  ว่า Index กับ View    
       - View   ว่าสร้างเพื่อให้  คนอื่น  ใช้งานง่าย หรือ จำกัด Security 
       - Index   ทำเพื่อความเร็วในการ Access 


CL - สร้างโปรแกรมช่วย ลดการทำงาน-1

CL - สร้างโปรแกรมช่วย ลดการทำงาน-1

CL = Control Language เป็นภาษาที่ใช้จัดการ  คำสั่ง  บน OS/400
ถ้าเทียบกับ Windows  ก็คือ เขียน/สร้าง Batch File เพื่อใช้คำสั่งย่อย ต่อเนื่องกัน

เทคนิคช่วยลด เวลา  ในการทำงานซ้ำๆได้ครับ

ตย. ทุกเดือนต้อง Backup Data  (เช่น Lib1/File1 -> LibB/FileH) โดยกำหนดขั้นตอนดังนี้
(1). แยกข้อมูลตาม ช่วงเวลา (เช่น  1 member ต่อ 6 เดือน เป็นต้น)
(2). เมื่อย้ายข้อมูลเสร็จ  จะนำข้อมูล
    2.1 จัดเก็บใน  Cartridge
    2.2 จัดเก็บใน  History Server (ที่ราคาถูกกว่า เช่น MS SQL Server)
          ต้องรวม Member กลับไปเป็น 1 Member
          (LibB/File1-หลาย member -> LibH/FileH 1 member)

ผมสนใจข้อ 2.2 ซึ่งต้องทำแบบ Manual ดังนี้
a. ตรวจดูว่า LibB/File1  มี member ชื่ออะไรบ้าง ? ด้วยคำสั่ง
    DSPFD  FILE(LibB/File1)  TYPE(*MBRLIST)
    (จดรายชื่อไว้)
b. Copy รวม data ด้วยคำสั่ง
    CPYF  FROMFILE(LibB/File1)   TOFILE(LibH/FileH)   FROMMBR(ระบุชื่อ)  TOMBR(*FIRST)   MBROPT(*ADD)

ตย. มี 10  File แต่ละ File มี 5-10  member ที่ชื่ออ่านยาก    การทำแบบ Manual  จะใช้เวลา "นาน" และเสี่ยงที่จะผิดพลาด (จดชื่อผิด)

เราจะสร้างโปรแกรมช่วย ลดการทำงาน ในข้อ 2.2 กัน
โดยสร้างโปรแกรม และทำงานดังนี้   CALL   BK2HT   (LibB   File1     LibH  FileH)

สร้าง CL  โดยปรับขั้นตอนตามนี้
(รับค่า   &LibB  &File1  &LibH  &FileH)
a. DSPFD FILE(&LibB/&File1) TYPE(*MBRLIST)  OUTPUT(*OUTFILE)  OUTFILE(QTEMP/A)
Loop อ่าน File  QTEMP/A
       b. CPYF  FROMFILE(&LibB/&File1)   TOFILE(&LibH/&FileH)  
                       FROMMBR
(&mlname)    TOMBR(*FIRST)   MBROPT(*ADD)

จากนั้น  เพิ่มรายละเอียดต่างๆ  เช่น
- ตรวจ Lib/File ต้องมี
- ถ้ามี File แต่ไม่มี Member
- ...

มาดู code  BK2HT แบบเต็มๆกัน

---------------------------------------------------------------------
PGM        PARM(&LIBB &FILE1  &LIBH  &FILEH)                  
                                             
DCLF       FILE(A)                    
DCL        VAR(&LIBB)    TYPE(*CHAR) LEN(10)  
DCL        VAR(&FILE1)   TYPE(*CHAR) LEN(10) 
DCL        VAR(&LIBH)    TYPE(*CHAR) LEN(10)  
DCL        VAR(&FILEH)  TYPE(*CHAR) LEN(10) 

CHKOBJ OBJ(&LIBB/&FILE1) OBJTYPE(*FILE)
MONMSG     MSGID(CPF9801) EXEC(GOTO CMDLBL(STP090)

CHKOBJ OBJ(&LIBH/&FILEH) OBJTYPE(*FILE)
MONMSG     MSGID(CPF9801) EXEC(GOTO CMDLBL(STP090)

DSPFD FILE(&LibB/&File1) TYPE(*MBRLIST)  OUTPUT(*OUTFILE)  OUTFILE(QTEMP/A)

/*-- Start Loop --*/
STP010:
  RCVF                                               
  MONMSG     MSGID(CPF0864) EXEC(GOTO CMDLBL(STP090))
  CPYF  FROMFILE(&LibB/&File1)   TOFILE(&LibH/&FileH)  
        FROMMBR
(&mlname)    TOMBR(*FIRST)   MBROPT(*ADD)

GOTO       CMDLBL(STP010)

/*-- End Loop --*/
STP090:
ENDPGM
---------------------------------------------------------------------
ก่อน compile  ให้เรียกใช้คำสั่งข้อ  a.  ก่อน (เพื่อสร้าง Object = QTemp/A)

อื่นๆ

เทคนิคนี้ใช้บ่อย   ได้กับงานที่เรียกใช้ CL Cmd ติดต่อกัน
- ตรวจ data size ในระบบ file ไหนมีขนาดใหญ่ เกินกำหนด
- ตรวจ job ที่ (กำลัง) ทำงานใน subsystem
- ...

ตย. ข้างต้น  เมื่อดุดีๆ  จะพบว่า  ถ้าปรับขั้นตอน  (1)  ให้ไปเก็บใน LibH/FileH 1 member เลย  ก็ไม่ต้องทำ 2.2     ที่ไม่ทำเพราะ  (1) เป็นโปรแกรมที่เก่ามาก  และมีเทคนิคเฉพาะหลายอย่าง ... การปรับถือว่าไม่คุ้ม