thongkorn โพสต์ 2017-11-4 12:25:08

[VB.NET] พื้นฐานการเขียนโปรแกรมแบบ CRUD (Create, Read, Update, Delete) กับตัวอย่างฐานข้อมูลผู้ป่วย MS Access

http://www.g2gnet.com/webboard/images/vbnet/PatientVB.png
ที่ต้องบอกว่าเป็นพื้นฐาน ก็เพราะว่าแอดมินจะใช้ตารางข้อมูลแบบเดี่ยวๆ โดยที่ไม่มีการสร้างความสัมพันธ์ใดๆระหว่างตารางข้อมูลเลย โดยจะเน้นแนวทางให้ศึกษาวิธีการ เพิ่มรายการใหม่ (Create) การอ่านหรือค้นคืน (Read/Retrieve) การปรับปรุง (Update) และการลบข้อมูล (Delete) ซึ่งเป็นพื้นฐานของการเขียนโปรแกรมเพื่อติดต่อกับฐานข้อมูล แต่โดยรวมๆการควบคุมโปรแกรม (Flow Control) จะเรียงลำดับขั้นตอนนี้ คือ
การค้นคืนข้อมูล จะมี 2 ลักษณะคือ
- หากไม่พบข้อข้อมูลที่ต้องการ ก็คือต้องไปทำการสร้างใหม่
- หากพบข้อมูล ก็จะมี 2 ทางเลือก คือ นำมาแก้ไข หรือ ลบข้อมูล
http://www.g2gnet.com/webboard/images/vbnet/PatientDB.png
การออกแบบตารางข้อมูลอย่างง่าย
จบภาคทฤษฎีเล็กๆ ก็จะมาว่ากันเรื่องการปฏิบัติ โดยเน้นการลงมือทำ อันเป็นหัวใจสำคัญของการเรียนรู้ ...

โค้ดในการค้นคืนข้อมูล ...
    ' / --------------------------------------------------------------------
    ' / Data Retrieval
    Private Sub RetrieveData(Optional ByVal blnSearch As Boolean = False)
      If blnSearch Then
            strSQL = _
                " SELECT Patient.HNPK, Patient.HN, Patient.PatientName, Patient.Address, Patient.Amphur, Patient.ProvinceName, Patient.PostCode, Patient.Telephone, Patient.BirthDate, Patient.Sex, Patient.Blood " & _
                " FROM(Patient) " & _
                " WHERE " & _
                " " & " Like '%" & txtSearch.Text & "%'" & " OR " & _
                " " & " Like '%" & txtSearch.Text & "%'" & " OR " & _
                " " & " Like '%" & txtSearch.Text & "%'" & " OR " & _
                " " & " Like '%" & txtSearch.Text & "%'" & " OR " & _
                " " & " Like '%" & txtSearch.Text & "%'" & " OR " & _
                " " & " Like '%" & txtSearch.Text & "%'" & " OR " & _
                " " & " Like '%" & txtSearch.Text & "%'" & " OR " & _
                " " & " Like '%" & txtSearch.Text & "%'" & " OR " & _
                " " & " Like '%" & txtSearch.Text & "%'" & _
                " ORDER BY Patient.HN "
      Else
            strSQL = _
                " SELECT Patient.HNPK, Patient.HN, Patient.PatientName, Patient.Address, Patient.Amphur, Patient.ProvinceName, " & _
                " Patient.PostCode, Patient.Telephone, Patient.BirthDate, Patient.Sex, Patient.Blood " & _
                " FROM(Patient) ORDER BY Patient.HN "
      End If
      DA = New OleDb.OleDbDataAdapter(strSQL, Conn)
      DS = New DataSet
      DS.Clear()
      DA.Fill(DS, "Patient")
      dgvData.DataSource = DS.Tables("Patient")
      lblRecordCount.Text = "[จำนวน : " & dgvData.RowCount & " รายการ]"
      '//
      DA.Dispose()
      DS.Dispose()
      Conn.Close()
      '//
      InitializeGrid()
      txtSearch.Clear()
    End Subจากโปรแกรมย่อย RetrieveData(Optional ByVal blnSearch As Boolean = False) เป็นเทคนิคในการเขียนโค้ดที่สามารถค้นหาและนำข้อมูลมาแสดงผลได้ในโปรแกรมย่อยตัวเดียวกัน โดยการกำหนดว่า หาก blnSearch = False จะเป็นการแสดงผลข้อมูลทั้งหมด แต่ถ้าหาก blnSearch = True จะเป็นการค้นหาข้อมูล ซึ่งการค้นหาข้อมูลจะมาจากการป้อนค่าใน TextBox

โค้ดการค้นหาข้อมูลที่ป้อนลงใน TextBox
    ' / --------------------------------------------------------------------
    Private Sub txtSearch_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtSearch.KeyPress
      '// ดักจับตัวอักขระอันไม่พึงปรารถนาสำหรับฐานข้อมูล เช่น ', * หรือ %
      txtSearch.Text = Replace(Trim(txtSearch.Text), "'", "")
      txtSearch.Text = Replace(Trim(txtSearch.Text), "%", "")
      txtSearch.Text = Replace(Trim(txtSearch.Text), "*", "")
      If Trim(txtSearch.Text) = "" Or Len(Trim(txtSearch.Text)) = 0 Then Exit Sub
      '// SearchData(True) หมายความว่า เป็นการค้นหาข้อมูล
      If e.KeyChar = Chr(13) Then '// Chr(13) คือ ASCII Code ของ Enter
            '// ปิดเสียงเตือน
            e.Handled = True
            Call RetrieveData(True)
      End If
    End SubRetrieveData(True) เพื่อระบุว่าเป็นการค้นหา

การเพิ่มข้อมูลใหม่ (Create)
โค้ดในส่วนของการสร้าง Primary Key เพื่อไม่ให้เกิดมีค่าที่ซ้ำกัน ... นิยามของ Primary Key หรือ PK คือกุญแจหลัก จะมีค่าที่ซ้ำกันไม่ได้ และเปลี่ยนแปลงค่าไม่ได้ การที่เปลี่ยนค่านี้ไม่ได้ ก็เพราะจะต้องนำคีย์หลักตัวนี้ไปเชื่อมต่อ หรือสร้างความสัมพันธ์เข้ากับตารางตัวอื่นๆ และที่สำคัญค่า PK เป็นค่าที่ผู้เขียนโปรแกรมจะต้องอ้างอิงไว้ใช้งาน
    ' / --------------------------------------------------------------------
    ' / ฟังค์ชั่นในการหาค่า Primary Key ตัวใหม่ไม่ให้ซ้ำกัน
    Function SetupNewPK(ByVal sql As String) As Long
      If Conn.State = ConnectionState.Closed Then Conn.Open()
      Cmd = New OleDb.OleDbCommand(sql, Conn)
      '/ ตรวจสอบว่ามีข้อมูลอยู่หรือไม่ และคืนค่ากลับ
      If IsDBNull(Cmd.ExecuteScalar) Then
            SetupNewPK = 1
      Else
            SetupNewPK = Cmd.ExecuteScalar + 1
      End If
    End Function
โค้ดในส่วนของการสร้าง ID หรือ IDentfier โดยไม่ให้เกิดมีค่าที่ซ้ำกัน ... แอดมินขอแนะนำให้แยกนิยามความหมายของคำว่า Primary Key ออกไปจาก IDentifier ซึ่งในที่นี้ ID ก็คือ HN หรือ Hospital Number ของผู้ป่วย
    ' / --------------------------------------------------------------------
    ' / ฟังค์ชั่นในการสร้างรหัสลูกค้า หรือ ID แบบอัตโนมัติ ตามรูปแบบที่เราต้องการ
    Function SetupAutoID() As String
      strSQL = _
            " SELECT MAX(Patient.HNPK) AS MaxPK FROM Patient "
      If Conn.State = ConnectionState.Closed Then Conn.Open()
      Cmd = New OleDb.OleDbCommand(strSQL, Conn)
      Dim MaxPK As Long
      '/ ตรวจสอบว่ามีข้อมูลอยู่หรือไม่
      If IsDBNull(Cmd.ExecuteScalar) Then
            MaxPK = 1
      Else
            MaxPK = Cmd.ExecuteScalar + 1
      End If
      '/ ตัวอย่างของการสร้างรูปแบบ ID อัตโนมัติ HN-ปีพ.ศ.XXXXX เช่น HN-6000013
      '/ เช่น ได้ MaxPK = 13 เอามาเรียงต่อกันกับ 0 จำนวน 5 ตัว ก็จะได้ "00000" & "13" = "0000013"
      '/ ให้นับกลับมาจากทางขวาเข้ามาทางซ้าย ก็จะได้ "00013"
      SetupAutoID = "HN-" & Microsoft.VisualBasic.Right(Year(Now), 2) & Microsoft.VisualBasic.Right("00000" & MaxPK, 5)
    End Function
ฟังค์ชั่นในการตรวจสอบค่า ID (หรือ HN) ว่ามีค่าที่ซ้ำกันหรือไม่ ... นิยามของ IDentifier หรือ รหัสผู้ป่วย (HN) จะมีค่าที่ซ้ำกันไม่ได้ แต่สามารถเปลี่ยนแปลงค่าได้ การที่มันสามารถเปลี่ยนแปลงค่าได้ ก็เพราะอาจจะเกิดการป้อนข้อมูลที่ผิดพลาดของผู้ใช้งาน และค่า HN จะเป็นค่าที่ Users เขาอ้างอิงถึงเสมอ
    ' / --------------------------------------------------------------------
    ' / ฟังค์ชั่นในการหาค่า ID ซ้ำกัน
    Public Function DuplicateID(ByVal Sql As String) As Boolean
      If Conn.State = ConnectionState.Closed Then Conn.Open()
      Cmd = New OleDb.OleDbCommand(Sql, Conn)
      ' Return count records
      DuplicateID = Cmd.ExecuteScalar
    End Function
เทคนิคในการดักตรวจสอบค่า HN เพื่อไม่ให้เกิดการซ้ำกันได้ สิ่งแรกคือต้องเก็บค่า HN ของเดิมเอาไว้ในตัวแปรตัวใดตัวหนึ่งก่อน แต่แอดมินใช้คุณสมบัติของ TextBox ที่มีชื่อว่า Tag เพื่อประหยัดตัวแปร ...
            txtHN.Text = "" & .Rows(0)("HN").ToString()
            '// เก็บค่า HN เดิมเอาไว้ เพื่อทำการเปรียบเทียบในภายหลัง
            txtHN.Tag = txtHN.Text- กรณีที่เพิ่มข้อมูลใหม่ ค่าใน Tag = "" แต่ต้องนำค่าคุณสมบัติใน Text ของ TextBox ไปเปรียบเทียบกับของเดิมที่มีอยู่ในตารางข้อมูล
- กรณีที่ทำการแก้ไข จะแบ่งเป็น 2 กรณี คือ
---- ค่าใน Tag = Text นั่นหมายความว่า ไม่มีการแก้ไขค่า HN ก็ให้ทำการบันทึกข้อมูลได้ทันที
---- ค่าใน Tag <> Text แสดงว่ามีการเปลี่ยนแปลงค่า HN ก็จะต้องไปเปรียบเทียบกับของเดิมที่มีอยู่ในตารางข้อมูล
      If txtHN.Text.ToLower <> LCase(txtHN.Tag) Then
            strSQL = _
                " SELECT Count(Patient.HN) AS CountHN FROM Patient " & _
                " WHERE HN = " & "'" & txtHN.Text & "'"
            If DuplicateID(strSQL) Then
                MessageBox.Show("HN มีค่าซ้ำ กรุณาแก้ไขใหม่ให้เรียบร้อยด้วย.", "รายงานความผิดพลาด", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                txtHN.Focus()
                Exit Sub
            End If
      End If
โค้ดในส่วนของการบันทึกข้อมูล ... สามารถกระทำได้ทั้งการเพิ่ม (Insert) หรือ การปรับปรุง (Update) ในโปรแกรมย่อยตัวเดียวกัน ก็เพราะแอดมินอาศัยตัวแปรแบบ Boolean ชื่อ NewData หากค่า NewData = True ก็คือการเพิ่มข้อมูลใหม่ หากเป็น False ก็คือการแก้ไข
    ' / --------------------------------------------------------------------
    ' / บันทึกข้อมูล
    ' / --------------------------------------------------------------------
    Private Sub SaveData()
      If NewData Then
            strSQL = _
                " INSERT INTO Patient(" & _
                " HNPK, HN, PatientName, Address, Amphur, ProvinceName, PostCode, Telephone, " & _
                " BirthDate, Sex, Blood, DateAdded, DateModified) " & _
                " VALUES('" & _
                SetupNewPK(" SELECT MAX(Patient.HNPK) AS MaxPK FROM Patient ") & "','" & _
                txtHN.Text & "','" & _
                txtPatientName.Text & "','" & _
                txtAddress.Text & "','" & _
                txtAmphur.Text & "','" & _
                txtProvinceName.Text & "','" & _
                txtPostCode.Text & "','" & _
                txtTelephone.Text & "','" & _
                dtpBirthDate.Value & "','" & _
                CheckSex() & "','" & _
                cmbBlood.Text & "','" & _
                Now & "','" & _
                Now & _
                "')"
            '// EDIT MODE
      Else
            '// START UPDATE
            strSQL = _
                " UPDATE Patient SET " & _
                " HN='" & txtHN.Text & "', " & _
                " PatientName='" & txtPatientName.Text & "', " & _
                " Address='" & txtAddress.Text & "', " & _
                " Amphur='" & txtAmphur.Text & "', " & _
                " ProvinceName='" & txtProvinceName.Text & "', " & _
                " PostCode='" & txtPostCode.Text & "', " & _
                " Telephone='" & txtTelephone.Text & "', " & _
                " BirthDate='" & dtpBirthDate.Value & "', " & _
                " Sex='" & CheckSex() & "', " & _
                " Blood='" & cmbBlood.Text & "', " & _
                " DateModified='" & Now & "'" & _
                " WHERE HNPK=" & PK & ""    ' ค่า PK จะได้มาจากการดับเบิ้ลคลิ๊กเลือกรายการแก้ไขเอาไว้แล้วล่วงหน้า
      End If
      '// การ Insert/Update กระทำเหมือนกัน
      If DoSQL(strSQL) Then
            MessageBox.Show("ปรับปรุงข้อมูลเรียบร้อย.", "รายงานสถานะ", MessageBoxButtons.OK, MessageBoxIcon.Information)
      End If
      '// แสดงข้อมูลในตารางกริดใหม่
      RetrieveData()'// Refresh
      '// ตั้งค่าโหมด
      NewMode()
    End Sub
แถมท้ายกับการเรียกข้อมูลมาแสดงผล ... แอดมินมีโค้ดอยู่ 2 ชุด เพื่อให้ศึกษาและเปรียบเทียบ โดยชุดจริงจะเป็นกรณีที่ใช้แบบ Multi-users ซึ่งจะต้องทำการ Query ข้อมูลเข้ามาใหม่ อีกชุดตามโค้ดด้านล่างจะเป็นแบบ Stand Alone โดยการเรียกข้อมูลมาแสดงผลจากตารางกริดแทน ซึ่งการเลือกไปใช้ในงานจริงๆ ก็อยู่ที่ว่าจะเป็นงานเล็กงานใหญ่กันล่ะครับ
    ' / --------------------------------------------------------------------
    ' / เรียกข้อมูลจาก DataGrid มาแสดงผล (กรณีใช้ Stand Alone)
    ' / --------------------------------------------------------------------
    Private Sub DataGridToScreen()
      '//
      Dim iRow As Integer
      '// อ่านค่าแถวที่ถูกโฟกัส
      iRow = dgvData.CurrentRow.Index
      '//
      PK = dgvData.Item(0, iRow).Value'// เก็บค่า Primary Key เอาไว้
      txtHN.Text = "" & dgvData.Item(1, iRow).Value
      '// เก็บค่า HN เดิมเอาไว้ เพื่อทำการเปรียบเทียบในภายหลัง
      txtHN.Tag = txtHN.Text
      '// การใช้ Double quote "" เพื่อดักค่าว่าง (แนวคิดดั้งเดิมมาตั้งแต่ VB6)
      txtPatientName.Text = "" & dgvData.Item(2, iRow).Value
      txtAddress.Text = "" & dgvData.Item(3, iRow).Value
      txtAmphur.Text = "" & dgvData.Item(4, iRow).Value
      txtProvinceName.Text = "" & dgvData.Item(5, iRow).Value
      txtPostCode.Text = "" & dgvData.Item(6, iRow).Value
      txtTelephone.Text = "" & dgvData.Item(7, iRow).Value
      '//
      dtpBirthDate.Value = dgvData.Item(8, iRow).Value
      lblAge.Text = CalcDate(dtpBirthDate.Value, Now)
      '//
      If dgvData.Item(9, iRow).Value = "ชาย" Then
            rbtSexM.Checked = True
      Else
            rbtSexF.Checked = True
      End If
      cmbBlood.Text = dgvData.Item(10, iRow).Value
    End SubConclusion: แอดมินก็หวังว่า คงจะเป็นแนวทางให้ได้เรียนรู้ศึกษากระบวนการขั้นตอนต่างๆ เพื่อให้ทุกๆท่านที่ได้เผลอเข้ามาอ่านกัน ได้รับความรู้ไปบ้างไม่เล็กก็น้อยก็ใหญ่ก็มากครับผม ... อนึ่ง!!! การได้เห็นโค้ด แต่ถ้าหากไม่ลองนำไปปฏิบัติจริง หรือคิดเพิ่มเติม ก็คงจะไม่มีประโยชน์อะไร ... สวัสดี

ดาวน์โหลดโค้ดต้นฉบับแบบเต็ม VB.NET (2010) ได้ที่นี่

Khim โพสต์ 2018-9-14 22:02:35

ดีมากเลยครับ แบ่งปันความรู้...
ขออนุญาตนำไปศึกษาและประยุกต์ใช้นะครับอาจารย์
ขอบพระคุณมากๆครับ

hot2 โพสต์ 2018-9-24 09:55:16

ค่อยจีบเมียใหม่ครับเฮีย
https://i.ytimg.com/vi/R9VA31rozLg/hqdefault.jpg

Phuvanart โพสต์ 2018-9-24 11:29:09

ขอบคุณครับ
ขออนุญาตินำไปศึกษาและพัฒนานะครับ

prawpun โพสต์ 2019-2-16 14:40:15

ขอบพระคุณคะ :)

yusanc โพสต์ 2019-7-15 10:57:11

ขอบคุณครับ:loveliness:

mukitti โพสต์ 2019-10-26 21:22:04

ขอบคุณครับ

komen โพสต์ 2019-11-12 22:04:01

ขอบคุณครับ อาจารย์

TanadpornPeadee โพสต์ 2019-12-1 20:04:05

ขอบคุณค่ะ

jaricha5 โพสต์ 2019-12-9 09:20:34

ขอบคุรครับ
หน้า: [1] 2
ดูในรูปแบบกติ: [VB.NET] พื้นฐานการเขียนโปรแกรมแบบ CRUD (Create, Read, Update, Delete) กับตัวอย่างฐานข้อมูลผู้ป่วย MS Access