หากมีคำถาม ขอให้ไปโพสต์ลง เว็บบอร์ดจีทูจีเน็ตดอตคอม ตัวใหม่แทนน่ะครับ

หรือติดต่อเข้ามาทาง Inbox ที่ เฟซบุ๊ค ผมครับ

หน้าหลัก
ข่าวสาร - บทความ ทั้งหมด
VB 6/VB.Net
ASP/ASP.Net
จับฉ่ายคอมพิวเตอร์
เรียนรู้ผ่าน Flash Movie
บทความที่มีผู้ตอบล่าสุด  
 RSS Feeds
 ดาวน์โหลดโปรแกรม RSS Reader ได้ที่นี่ ...   Download โปรแกรม RSS Reader

Forum - www.g2gnet.com
Webmaster - www.g2gnet.com
Visitors - Session views
 5 3 5 7 6 6 6

7 ธันวาคม พ.ศ.2549
136 Users On-Line.
Visitors - Page views
 8 6 9 3 9 7 8
1 กุมภาพันธ์ พ.ศ.2551

Google   
เว็บ g2gnet.com
ขนาดตัวอักษร:  

เรียนรู้ Visual Basic 6.0 กับ ฐานข้อมูล MS Access ภาค 10 (การทำรายงาน)

Category »  VB 6/VB.Net
โดย : Webmaster เมื่อ 27/7/2550 1:59:00
(อ่าน : 41059) 

เมื่อไปงานเลี้ยงแบบโต๊ะจีน เวลาเขามาเสิร์ฟพวกผลไม้ หรือ ของหวาน นั่นแหละรู้เลยว่างานเลี้ยงกำลังจะเลิกรา (แหมกำลังได้ที่เลย ... แบบนี้ต้องหาที่ไปต่อ 55555) ฉันใดก็ฉันนั้น เมื่อเขียนโปรแกรมจนได้ผลงานออกมาตามที่ต้องการ รวมไปถึงการทดสอบเพื่อหาข้อผิดพลาดต่างๆแล้ว ต่อมาก็คือ การทำรายงาน (Report) เป็นกระบวนการในขั้นตอนสุดท้าย และไม่ว่าท่านจะใช้งาน ActiveX Report ของค่ายใดๆก็ตามแต่ แท้จริงนั้น Concept หรือ หลักการ (หลักๆ) ของ (พวก) มันก็คล้ายๆกันทั้งหมด ประเด็นสำคัญๆนั่นก็คือ

      1. ดึงฟิลด์ข้อมูลต่างๆมายัดใส่ไว้ใน SQL Statement หรือที่เรียกกันว่า QUERY ซึ่งตรงนี้แหละที่จะประกอบไปด้วยสูตร สมการ เงื่อนไข การคำนวณต่างๆ เข้ามาประกอบกัน (เนื้อๆเน้นๆ มันก็คือเรื่อง DataBase)
      2. ส่งฟิลด์ข้อมูลต่างๆ ไปให้กับ Control ที่อยู่บนแบบฟอร์มรายงานเพื่อทำการแสดงผล
ผมเลยเลือก Data Report มาเป็น Case Study เพื่อให้พี่น้องได้ทำการศึกษาเป็นแนวทาง (ที่นำไปใช้งานจริงๆได้เลย) หากทำความเข้าใจในส่วนนี้ได้อย่างถ่องแท้แล้ว กับ Crystal Report หรือ Active Report น่ะมันแค่เรื่องประติ๋วไปเลย ... นี่แหละผมถึงบอกว่า "พื้นฐาน" มันเป็นเรื่องที่สำคัญ สำคัญที่มันจะนำไปใช้ "ต่อยอด" ได้

 

การทำรายงานใน Data Report โดยไม่ใช้ DataEnvironment

ผมจะใช้โปรแกรมของเดิมในภาค 8 มาต่อยอด เพื่อทำรายงานใน Data Report นำเสนอให้กับพี่น้องได้ดู ได้ชม หรือ จะดมก็สุดแท้แต่ท่านก็แล้วกัน แน่นอนครับงานชิ้นนี้ผมจะไม่ผูกติด Control ไว้กับฟิลด์ใดๆในตารางข้อมูลเลยในขณะออกแบบ หรือ Design Time เราจะอาศัยการทำงานของโปรแกรมที่เรียกว่า "RUN-TIME" นั่นคือ เราจะเห็นผลลัพธ์ของการทำงานของโปรแกรม ก็ต่อเมื่อเราสั่งโปรแกรมให้ทำงานแล้วเท่านั้น ซึ่งจากตัวอย่างที่จะได้รับชมต่อไปนี้ บอกได้เลยว่า "เอาไปทำมาหากินได้" อย่างไม่ต้องไปอายใครเขาแน่นอน


เริ่มจากการเพิ่มตัวรายงานเข้ามา (คลิ๊กเมาส์ขวาแล้วทำการเลือก Data Report)

      ส่วนใหญ่ท่านก็คงจะมีหนังสือกอดไว้แนบกับอกกันแล้วทั้งนั้น ... ผมก็ขออธิบายเกี่ยวกับโครงสร้างของพื้นที่รายงานแบบคร่าวๆก็พอน่ะครับ ... พี่น้อง
      Report Header ก็ปรากฏเป็นส่วนหัวของรายงาน ซึ่งจะอยู่หน้าแรกเท่านั้น
      Page Header เป็นส่วนหัวของหน้ารายงานทุกๆหน้า เช่น ป้ายบอกรหัสลูกค้า ชื่อ - นามสกุล
      Detail นี่แหละส่วนสำคัญที่ต้องแสดงข้อมูลออกมา
      Report Footer เป็นส่วนท้ายสุดของรายงาน มีที่หน้าสุดท้ายของรายงานเท่านั้น (คู่กับ Header)
      Page Footer เป็นส่วนท้ายของหน้ารายงานทุกๆหน้า ก็เอาไว้แสดงพวกหมายเลขหน้า

ลาก Control มาวางไว้บนรายงาน (สนใจแต่เพียง TextBox เป็นหลักน่ะครับ)


ประเด็นที่สำคัญคือ TextBox ที่เอามาวางไว้นั้นมันจะทำการรับค่าเพื่อมาแสดงผล
และะแบบไม่ต้องผูกติดคอนโทรล (UnBound) ใดๆทั้งสิ้น


การเสริมแต่งออพชั่นเข้าไปให้ดูดีมีชาติตระกูล (แบบไอ้หงิก)


ผลที่ได้จากการรันโปรแกรม แจ่มบ้างมั้ยครับ ... พี่น้อง
ใครจะไปคิดว่ามันมาจาก Data Report เหอๆๆๆๆ

   ดาวน์โหลด Source Code สำหรับ MS Visual Basic 6.0 - Service Pack 6

กล่าวง่ายๆเลย ในภาคนี้ผมจะเอาข้อมูลที่อยู่ในตาราง FlexGrid มาพิมพ์รายงาน


' จากภาค 8 จะมีส่วนเพิ่มเติมแก้ไขขึ้นมาดังนี้
Option Explicit
' ประกาศตัวแปรให้มองเห็นทั่วทั้งฟอร์ม
' ไว้รับค่าของการค้นหา
Dim Criteria As String

โปรแกรมย่อยเพื่อทำการค้นหาข้อมูล หาได้แล้วก็จะเอาไปพิมพ์รายงานนี่แหละคร้าบผม
Private Sub cmdSearch_Click()
If Trim(txtSearch.Text) = "" Or Len(Trim(txtSearch.Text)) = 0 Then
    txtSearch.SetFocus
    Exit Sub
End If

' ส่งค่าจาก txtSearch ไปเก็บไว้ในตัวแปร Criteria
' txtSearch มีค่าอะไร Criteria ก็ต้องมีค่าตามนั้น (แต่ต้องหลังจากกดปุ่ม cmdSearch น่ะครับ)
Criteria = Trim(txtSearch.Text)
'
Dim CountRec As Long, item As Long
Set RS = New ADODB.Recordset
' เวอร์ชั่นนี้ผมเพิ่มการค้นหา CustomerID เข้ามาแล้วน่ะครับ
Statement = "SELECT tblCustomer.*, tblTitle.TitleName " & _
                        " FROM tblCustomer INNER JOIN tblTitle ON tblCustomer.TitleID = tblTitle.TitleID " & _
                        " WHERE " & _
                            " [CustomerID] " & " Like '%" & Trim(txtSearch.Text) & "%'" & " OR " & _
                            " [FirstName] " & " Like '%" & Trim(txtSearch.Text) & "%'" & " OR " & _
                            " ..................... & _
                            " ORDER BY CustomerID "

RS.CursorLocation = adUseClient
...
...
...
...
RS.Close
Set RS = Nothing
End Sub

โปรแกรมย่อยเพื่อแสดงข้อมูลใหม่ทั้งหมด แล้วก็จะเอาไปพิมพ์รายงานนี่แหละขอรับ
Private Sub cmdRefresh_Click()
    txtSearch.Text = ""
    ' txtSearch มีค่าอะไร Criteria ก็ต้องมีค่าตามนั้น (แต่ต้องหลังจากกดปุ่ม cmdRefresh น่ะครับ)
    Criteria = ""
    Call SetupFgCustomer
    Call DisplayFgCustomer
End Sub

ขั้นตอนของการนำข้อมูลมาพิมพ์ออกเป็นรายงาน


Private Sub cmdPrintReport_Click()
    
    Set RS = New Recordset
    ' SQL Statement นี้เราสามารถนำไปประยุกต์ใช้ได้เยอะมาก ลองดูกับตารางกริดได้เลย
    Statement = "SELECT " & _
    " Right$('0000000' & [tblCustomer.CustomerID], 7) AS CusID, " & _
    " [FirstName] & '  ' & [LastName] AS Name, " & _
    " [tblCustomer.Address] &  CHR(32) & CHR(32) & [tblCustomer.Amphur] & CHR(10) & " & _
    " IIF([tblProvince.ProvinceName]='กรุงเทพมหานคร', [tblProvince.ProvinceName],
    'จ.' & [tblProvince.ProvinceName]) & ' ' & " & _ " [tblCustomer.PostCode] AS Address " & _ " FROM tblCustomer INNER JOIN tblProvince ON tblCustomer.ProvinceID = tblProvince.ProvinceID " ' จาก SQL Statement ' CHR(32) หรือ 20H (ฐาน 16) รหัส ASCII Code ตัวนี้คือ Space หรือ ช่องว่าง มีค่าเท่ากับ ' ' ' CHR(10) หรือ 0AH (ฐาน 16) คือ การเลื่อนบรรทัดใหม่ (Line Feed) ' Right$('0000000' & [tblCustomer.CustomerID], 7) AS CusID ' การผสมของ String เช่น CustomerID = 1 ดังนั้นเมื่อ '0000000' & 1 ก็จะได้ '00000001' คือ 8 หลัก ' จากนั้นให้นับความยาวจากทางขวามือมา 7 ตัว (หรือหลัก) ... พร้อมกับตั้งชื่อฟิลด์เพื่ออ้างถึง คือ CusID ' [FirstName] & ' ' & [LastName] AS Name เป็นการรวมฟิลด์ (Merge) เข้าด้วยกัน ' แล้วตั้งชื่อฟิลด์ของการรวมใหม่ให้มันดังตัวอย่าง คือ Name ' กรณีของ MySQL หากจำไม่ผิดมันใช้ CONCAT (ConCatenate) เข้าช่วยครับผม ' IIF(การทดสอบเงื่อนไข, จริง, เท็จ) ' หากเป็นจริง หรือ tblProvince.ProvinceName = 'กรุงเทพมหานคร' ก็สั่งให้พิมพ์กรุงเทพมหานครเลย ' หากเป็นเท็จ ก็เลยต้องสั่งพิมพ์ 'จ.' นำหน้า ตามด้วย tblProvince.ProvinceName ' =================================================================== ' เห็นข้อดีของการแยกตารางย่อยออกมาหรือยังครับ ... tblCustomer - tblProvince ' นอกจากจะประหยัดพื้นที่หน่วยความจำ สะดวกต่อผู้ใช้งาน แล้วยังสะดวกต่อผู้พัฒนาโปรแกรมด้วย ' และผมไม่เคยอ้างถึง Normalization เพราะอธิบายจนหัวหงอกก็ไม่รู้เรื่อง ... 55555555555555555 ' =================================================================== ' หากมีการค้นหาข้อมูล Criteria จะมีค่าเท่ากับ txtSearch.Text ' เหตุผลที่ต้องเอาค่าจาก txtSearch.Text ไปเก็บไว้ในตัวแปร Criteria ก็เผื่อถ้าหากผู้ใช้งานไปเปลี่ยนค่า ' ใน txtSearch.Text แต่ไม่ได้กดปุ่มค้นหา (cmdSearch) ' พูดง่ายๆ มันเหมือนกับว่าเราจะเอาข้อมูลจาก FlexGrid มาพิมพ์นั่นเอง ... พี่น้อง 55555 ' และเวอร์ชั่นนี้ผมเพิ่มการค้นหา CustomerID เข้ามาแล้วน่ะครับ If Criteria <> "" Then ' แสดงว่ามีการค้นหาข้อมูลมาใส่ในตารางกริด Statement = Statement & _ " WHERE " & _ " [CustomerID] " & " Like '%" & Criteria & "%'" & " OR " & _ " [FirstName] " & " Like '%" & Criteria & "%'" & " OR " & _ " [LastName] " & " Like '%" & Criteria & "%'" & _ " ORDER BY CustomerID " Else ' จัดเรียงข้อมูลตามหมายเลข CustomerID Statement = Statement & " ORDER BY CustomerID " End If RS.CursorLocation = adUseClient RS.Open Statement, ConnMyDB, adOpenForwardOnly, adLockReadOnly, adCmdText ' ไม่มีข้อมูลก็จบการทำงานของมันซ่ะ ... เสียเวลา If RS.RecordCount <= 0 Then MsgBox "ไม่มีข้อมูลในการพิมพ์รายงาน.", vbOKOnly + vbExclamation, "รายงานสถานะ" RS.Close: Set RS = Nothing Exit Sub End If ' ตั้งค่าระยะการพิมพ์แบบ Run-Time With rptCustomer .LeftMargin = 1440 .TopMargin = 1440 ' กระดาษ A4 (210 mm x 297 mm หรือ 11907 twips x 16840 twips). ' หน่วยการวัด 1440 Twip = 1 นิ้ว หรือ 25.4 มิลลิเมตร (โดยประมาณ) ' หรือ 567 twips = 1 cm. ' สมมุติน่ะครับ สมมุติ ต้องการหน่วยวัดเป็นมิลลิเมตร ' ให้ขอบขวา 15 มม. ก็กลับสูตรบัญญัติไตรยางค์ดูครับพี่น้อง ... .RightMargin = (1440 * 15) / 25.4 '.ReportWidth = Printer.Width - .LeftMargin - .RightMargin ' ตั้งค่ากระดาษแบบแนวตั้ง .Orientation = rptOrientPortrait End With ' เริ่มผูกฟิลด์ข้อมูลส่งไปให้กับ TextBox ที่อยู่ใน rptCustomer ' ลักษณะการทำงานแบบนี้เราเรียกว่า Run Time น่ะครับ ... พี่น้อง With rptCustomer ' ผูกตาราง (RecordSet) ให้กับรายงาน Set .DataSource = RS With .Sections("Section1").Controls' ก็บริเวณ Detail ล่ะครับ ' อ้างถึงฟิลด์ CusID ประกอบด้วยการรวมของ String ขนาด 7 หลัก .item("txtCustomerID").DataField = RS.Fields(0).Name ' ฟิลด์ Name ประกอบด้วยชื่อ และ นามสกุล .item("txtCustomerName").DataField = RS.Fields(1).Name ' ฟิลด์ Address ประกอบด้วยที่อยู่ อำเภอ จังหวัด และ รหัสไปรษณีย์ .item("txtAddress").DataField = RS.Fields(2).Name End With End With ' เปิดฟอร์มรายงานแบบเต็มจอ rptCustomer.WindowState = vbMaximized ' แสดงผลรายงาน rptCustomer.Show vbModal ' เมื่อเลิกใช้งานเราก็ต้องปิดมันซ่ะ RS.Close: Set RS = Nothing End Sub

Conclusion:
จะเห็นได้ว่าหากเราต้องการคำนวณหาค่า เช่น Sum, Average หรืออื่นๆ ก็เพียงแต่กำหนดจาก SQL Statement (Query) ก็จะสามารถแก้โจทย์ปัญหาต่างๆได้อย่างไ่ม่ยากเย็นนัก สำหรับภาคนี้ผมได้วาง Bug หรือการเกิดข้อผิดพลาดบางประการขึ้น ที่เราเรียกว่า "Logical Error" คือ โปรแกรมทำงานฉลุยทุกอย่าง แต่ได้คำตอบที่ไม่ตรงกับความต้องการ (ดังภาพด้านล่าง) ซึ่งการเกิด Error ในลักษณะแบบนี้เป็นการแก้ไขความผิดพลาดที่ยากที่สุดครับ

  • Syntax Error - การพิมพ์คำสั่งผิดไม่ตรงไวยากรณ์ (Syntax) ของแต่ละภาษา
  • Run Time Error - โปรแกรมผิดพลาดในระหว่างของการทำงาน ปกติเราจะ Trap Error เพื่อแก้ปัญหา
  • Logical Error เจ้านี่แหละยากสุดครับ ... การป้องกัน คือ พยายามออกแบบงานต่างๆให้รอบคอบ รัดกุม ให้เป็นระบบ
เวลามันค้นหาข้อมูลแสดงผลในตารางกริดได้ถูกต้อง แต่เวลาตอนพิมพ์เป็นรายงานกลับมาไม่ครบ สาเหตุคือว่า ผมไม่ได้ดึงข้อมูลจากตารางคำนำหน้า (tblTitle) เข้ามาด้วย ตรง ดร. นี่แหละที่เป็นคำนำหน้า ... ก็ขอให้พี่น้องลองแก้ไขดูครับ ไม่ยากหรอก

 


ผมสร้าง Bug เอาไว้ให้แก้กันเล่นๆ


นั่นแหละข้อมูลที่หายไป ... เนื่องจากผมไม่ได้ดึงตารางคำนำหน้า (tblTitle) เข้ามาด้วย

อีกอย่างที่ผมอยากให้พี่น้องได้ลองแก้ไขดู ก็คือทำยังไงให้มีคำว่า "อ." นำหน้าชื่ออำเภอ สำหรับจังหวัดที่ไม่ใช่กรุงเทพมหานคร ส่วนกรุงเทพฯให้ใช้ "เขต" นำหน้าแทน ... ลองทำดูครับ ไม่ยากเกินไปนักหรอก ... ขอให้ประเทศชาติเรามีโปรแกรมเมอร์เก่งๆเพิ่มขึ้นอีกเยอะๆด้วยครับ ...


จี ทู จี เน็ต ดอต คอม - g2gNet Dot Com
เลขทะเบียนพาณิชย์อิเล็กทรอนิกส์ 0407314800231
CopyLeft © 2004 - 2099 g2gNet.Com All rights reserved.
Email: [email protected] หรือ โทร. 08-6862-6560